<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-7964484936470829118</id><updated>2012-02-16T19:28:12.476+09:00</updated><category term='rest'/><category term='goldenport'/><category term='voltdb'/><category term='android'/><category term='scala'/><category term='smartdox'/><category term='akakusa'/><category term='scalaz'/><category term='java'/><category term='simplemodeling'/><category term='simplemodeler'/><category term='fp'/><category term='websocket'/><category term='tips'/><category term='mindmapmodeling'/><category term='g3'/><category term='ofp'/><category term='java ee'/><category term='g4'/><category term='F#'/><category term='architecture'/><category term='hbase'/><category term='hadoop'/><title type='text'>Modegramming Style</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://modegramming.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://modegramming.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>asami</name><uri>http://www.blogger.com/profile/12083671403528595185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_4HtJQwbXqEY/S4sSwhKz5fI/AAAAAAAAAFs/IvXW6ca5RGE/S220/profile.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>88</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-7964484936470829118.post-5981735402712995588</id><published>2012-02-16T08:00:00.000+09:00</published><updated>2012-02-16T08:00:05.077+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tips'/><category scheme='http://www.blogger.com/atom/ns#' term='scalaz'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>Scala Tips / Either (4) - getOrElse, flatMap</title><content type='html'>&lt;div&gt;&lt;p&gt;Eitherから値を取り出すイディオムです。&lt;/p&gt;&lt;p&gt;Eitherから値を取り出す処理として以下の2つのコーディングパターンを挙げました。&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Either[A, B]からEither[A, C]に変換&lt;/li&gt;&lt;li&gt;Eigher[A, B]からCに変換&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;前回は、後者のEither[A, B]からCへの変換について、基本的なイディオムを紹介しました。&lt;/p&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;条件&lt;/th&gt;&lt;th&gt;結果&lt;/th&gt;&lt;th&gt;演算&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Either[A, B]がRight[A, B]&lt;/td&gt;&lt;td&gt;C&lt;/td&gt;&lt;td&gt;BからCを計算&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Either[A, B]がLeft[A, B]&lt;/td&gt;&lt;td&gt;C&lt;/td&gt;&lt;td&gt;デフォルト値&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;今回は、Either[A, B]がLeft[A, B]の場合だけでなく、Right[A, B]の値が条件を満たさない場合も、デフォルト値を返すようにします。&lt;/p&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;条件&lt;/th&gt;&lt;th&gt;結果&lt;/th&gt;&lt;th&gt;演算&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Either[A, B]がRight[A, B]で有効な値が入っている&lt;/td&gt;&lt;td&gt;C&lt;/td&gt;&lt;td&gt;BからCを計算&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Either[A, B]がRight[A, B]で無効な値が入っている&lt;/td&gt;&lt;td&gt;C&lt;/td&gt;&lt;td&gt;デフォルト値&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Either[A, B]がLeft[A, B]&lt;/td&gt;&lt;td&gt;C&lt;/td&gt;&lt;td&gt;デフォルト値&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;以下では、Either[Exception, Int]からStringへの変換を例に考えてみます。ただし、Intは0以上のものが有効という条件を追加します。Right[Int]に入っているIntが0以上の場合、Stringが処理結果となります。一方、0未満の場合は無効となり空文字列「&amp;quot;&amp;quot;」が処理結果となります。またEither[A, B]がLeft[A, B]の場合も空文字列「&amp;quot;&amp;quot;」が処理結果となります。&lt;/p&gt;&lt;p&gt;(&lt;a href="http://modegramming.blogspot.com/2012/01/scala-tipsoption.html"&gt;分類の基準&lt;/a&gt;)&lt;/p&gt;&lt;div&gt;&lt;h4&gt;Java風&lt;/h4&gt;&lt;p&gt;if式でEither#isRightを使って右側の値の有無を判定します。デフォルト値の「&amp;quot;&amp;quot;」はelse句で指定します。isRightメソッドが一回、getメソッドが二回、泣き別れになってしまいます。&lt;/p&gt;&lt;pre name="code" class="java"&gt;def f(a: Either[Exception, Int]): String = {&lt;br /&gt;  if (a.isRight &amp;amp;&amp;amp; a.right.get.toString &amp;gt;= 0) {&lt;br /&gt;    a.right.get.toString&lt;br /&gt;  } else &amp;quot;&amp;quot;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;Scala風&lt;/h4&gt;&lt;p&gt;match式を使うと以下のようになります。こちらの方が綺麗です。&lt;/p&gt;&lt;pre name="code" class="java"&gt;def f(a: Either[Exception, Int]): String = {&lt;br /&gt;  a match {&lt;br /&gt;    case Right(b) if b &amp;gt;= 0 =&amp;gt; b.toString&lt;br /&gt;    case _ =&amp;gt; &amp;quot;&amp;quot;&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;Scala&lt;/h4&gt;&lt;p&gt;EitherでMonadic演算をしたい場合にはright(またはleft)メソッドでRightProjection(またはLeftProjection)を取得し、これに対してmapメソッドやflatMapメソッドを適用します。EitherとRightProjection/LeftProjectionの組合せでモナド的な動作をします。&lt;/p&gt;&lt;p&gt;前回は計算文脈の切り替えは行わなかったのでmapメソッドを使いましたが、今回は計算文脈の切り替えを行うのでflatMapメソッドを使います。&lt;/p&gt;&lt;p&gt;以下ではEitherからrightメソッドでRightProjectionを取り出しflatMapメソッド内で、Right[Exception, Int]の値が0未満である場合はLeft(new IllegalArgumentException(&amp;quot;bad&amp;quot;))を返すことで失敗の計算文脈に切り替える処理を行っています。&lt;/p&gt;&lt;pre name="code" class="java"&gt;def f(a: Either[Exception, Int]): String = {&lt;br /&gt;  a.right.flatMap { b =&amp;gt;&lt;br /&gt;    if (b &amp;gt;= 0) Right(b.toString)&lt;br /&gt;    else Left(new IllegalArgumentException(&amp;quot;bad&amp;quot;))&lt;br /&gt;  }.right getOrElse &amp;quot;&amp;quot;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div&gt;&lt;h5&gt;Optionに変換&lt;/h5&gt;&lt;p&gt;最終的に値を取り出す場合、左側に保持しているエラー情報は捨てることになります。この場合には、エラー情報(Exception)を最初の段階で捨ててしまい、エラーか否かという情報のみを伝搬しても得られる結果は同じです。&lt;/p&gt;&lt;p&gt;前述の例では、new IllegalArgumentException(&amp;quot;bad&amp;quot;)で生成したExceptionを次の処理ですぐに捨てています。もったいないですね。&lt;/p&gt;&lt;p&gt;以下ではRightProjectionのtoOptionメソッドでEitherをOptionに変換してしまいます。Optionに変換後、withFilterメソッド、mapメソッドとgetOrElseメソッドの合わせ技で値を取得しています。&lt;/p&gt;&lt;pre name="code" class="java"&gt;def f(a: Either[Exception, Int]): String = {&lt;br /&gt;  a.right.toOption.withFilter(_ &amp;gt;= 0).map(_.toString) getOrElse &amp;quot;&amp;quot;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;Scalaz&lt;/h4&gt;&lt;p&gt;ScalazではEitherが右側を成功文脈とする成功/失敗の計算文脈としても動作するので、Either#rightメソッドでRightProjectionを取得しなくてもEitherに対して直接flatMapメソッドを適用することができます。ただし、ScalazでもEither#getOrElseメソッドはないので、rightメソッドでRightProjectionを取得する必要があります。このためScala版と比べてそれほど違いは出てきません。&lt;/p&gt;&lt;pre name="code" class="java"&gt;def f(a: Either[Exception, Int]): String = {&lt;br /&gt;  a.flatMap { b =&amp;gt;&lt;br /&gt;    if (b &amp;gt;= 0) b.toString.right&lt;br /&gt;    else new IllegalArgumentException(&amp;quot;bad&amp;quot;).left&lt;br /&gt;  }.right getOrElse &amp;quot;&amp;quot;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;また、Booleanのeitherメソッドを使う方法もあります。&lt;/p&gt;&lt;pre name="code" class="java"&gt;def f(a: Either[Exception, Int]): String = {&lt;br /&gt;  a.flatMap { b =&amp;gt;&lt;br /&gt;    !(b &amp;gt;= 0) either {&lt;br /&gt;      new IllegalArgumentException(&amp;quot;bad&amp;quot;)&lt;br /&gt;    } or b.toString&lt;br /&gt;  }.right getOrElse &amp;quot;&amp;quot;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;SclazではflatMapを「&amp;gt;&amp;gt;=」の記号で記述することができます。上の例はそれぞれ以下のようになります。&lt;/p&gt;&lt;pre name="code" class="java"&gt;def f(a: Either[Exception, Int]): String = {&lt;br /&gt;  (a &amp;gt;&amp;gt;= { b =&amp;gt;&lt;br /&gt;    if (b &amp;gt;= 0) b.toString.right&lt;br /&gt;    else new IllegalArgumentException(&amp;quot;bad&amp;quot;).left&lt;br /&gt;  }).right getOrElse &amp;quot;&amp;quot;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;pre name="code" class="java"&gt;def f(a: Either[Exception, Int]): String = {&lt;br /&gt;  (a &amp;gt;&amp;gt;= { b =&amp;gt;&lt;br /&gt;    !(b &amp;gt;= 0) either {&lt;br /&gt;      new IllegalArgumentException(&amp;quot;bad&amp;quot;)&lt;br /&gt;    } or b.toString&lt;br /&gt;  }).right getOrElse &amp;quot;&amp;quot;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div&gt;&lt;h5&gt;Optionに変換&lt;/h5&gt;&lt;p&gt;ScalazでもEitherにtoOptionメソッドは追加されないのでrightメソッドで得られるRightProjectionのtoOptionメソッドを用いてOptionに変換します。&lt;/p&gt;&lt;pre name="code" class="java"&gt;def f(a: Either[Exception, Int]): String = {&lt;br /&gt;  a.right.toOption.withFilter(_ &amp;gt;= 0).map(_.toString) | &amp;quot;&amp;quot;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Scalazでは、Optionに対して色々な機能拡張を行っているので、Optionに変換すればいろいろな技を使うことが可能になります。ここでは「|」メソッドで値を取り出しています。&lt;/p&gt;&lt;p&gt;また、以下のようにデフォルト値が&lt;a href="http://modegramming.blogspot.com/2012/02/scala-tips-option-8.html"&gt;モノイドの単位元と同じ場合にはorZeroメソッド&lt;/a&gt;を使うこともできます。&lt;/p&gt;&lt;pre name="code" class="java"&gt;def f(a: Either[Exception, Int]): String = {&lt;br /&gt;  a.right.toOption.withFilter(_ &amp;gt;= 0).map(_.toString) orZero&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;ノート&lt;/h4&gt;&lt;p&gt;前回のmapメソッドと同様に、flatMapメソッドを使う場合も、計算文脈をEitherからOptionに切り替えるテクニックが有力です。&lt;/p&gt;&lt;p&gt;Eitherを使う場合は、計算文脈を成功文脈から失敗文脈に切り替える時にflatMapメソッドを使うしか選択肢はありませんが、Optionにすることで、withFilterメソッドやcollectメソッドなども使えるようになります。&lt;/p&gt;&lt;p&gt;また、ScalazはOptionに対して色々な機能拡張をしているので、さらにプログラミングの選択肢が広がります。今回の例では「|」メソッドやorZeroメソッドで値を取り出しています。&lt;/p&gt;&lt;p&gt;Monadicプログラミングでは、計算文脈の中で文脈を切り替えていく(Eitherの中でLeftとRightを切り替え)のに加え、計算文脈毎、応用に適したものに切り替えていく(EitherをOptionに切り替え)のも重要なテクニックになります。&lt;/p&gt;&lt;p&gt;モナドで実現された階層化複合化された計算文脈を適材適所で切り替えながら処理を進めていくのがMonadicプログラミングの醍醐味と言えるかもしれません。&lt;/p&gt;&lt;div&gt;&lt;h5&gt;flatMapと「&amp;gt;&amp;gt;=」と「∗」&lt;/h5&gt;&lt;p&gt;Scalazは型クラスをベースにしたMonadicプログラミングを指向したクラスライブラリですが、Scala言語本体にもモナドが実装されています。このため、モナドの基本操作の部分ではScala本体とScalazの機能がバッティングします。&lt;/p&gt;&lt;p&gt;ボク個人のプログラミング方針としては、Scala本体とScalazがバッティングしていて機能がほとんど変わらない場合はScala本体を選ぶようにしています。というのは、Scalazは余分なオブジェクトを相当数生成しながら動作するのでかなり重たいからです。&lt;/p&gt;&lt;p&gt;ただ、これは簡潔に記述できることとのトレードオフでもありますし、Scalazを選んだ以上多少のことは目をつぶって簡潔さに賭けるというのが潔く、現在のハードウェア性能では多くの場合許容範囲と考えられます。&lt;/p&gt;&lt;p&gt;さらに本記事のようなScalazイディオムという意味では、よりScalazらしい書き方を主にした方が趣旨に合います。&lt;/p&gt;&lt;p&gt;そういうこともあって、ボクの書き癖でflatMapを使ってきましたが、Scalazらしく機能がバッティングする場合も「&amp;gt;&amp;gt;=」といったScalaz側のメソッドを主にしていくことにしました。&lt;/p&gt;&lt;p&gt;また、flatMapは「∗」、mapは「∘」という記号(Unicode)で記述する方法もあり、flatMap、「&amp;gt;&amp;gt;=」、「∗」のどれを選ぶのか悩ましいところです。「∗」は「∘」と紛らわしいので、flatMap、「&amp;gt;&amp;gt;=」、「∗」の選択では「&amp;gt;&amp;gt;=」を使うことにします。(Haskellの流儀に則っていて、モナドや型クラス周りの知識のある人には読みやすいというのもあります。)&lt;/p&gt;&lt;p&gt;なお、Eitherに関していうと、Scala標準ではEitherにはflatMapメソッドはないので、Scalazを使っていることを明示する目的で「&amp;gt;&amp;gt;=」を使うという考え方もあります。&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;諸元&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Scala 2.9.1&lt;/li&gt;&lt;li&gt;Scalaz 6.0.3&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7964484936470829118-5981735402712995588?l=modegramming.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://modegramming.blogspot.com/feeds/5981735402712995588/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://modegramming.blogspot.com/2012/02/scala-tips-either-4-getorelse-flatmap.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/5981735402712995588'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/5981735402712995588'/><link rel='alternate' type='text/html' href='http://modegramming.blogspot.com/2012/02/scala-tips-either-4-getorelse-flatmap.html' title='Scala Tips / Either (4) - getOrElse, flatMap'/><author><name>asami</name><uri>http://www.blogger.com/profile/12083671403528595185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_4HtJQwbXqEY/S4sSwhKz5fI/AAAAAAAAAFs/IvXW6ca5RGE/S220/profile.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7964484936470829118.post-7884899701006454175</id><published>2012-02-15T08:00:00.000+09:00</published><updated>2012-02-15T09:17:35.333+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tips'/><category scheme='http://www.blogger.com/atom/ns#' term='scalaz'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>Scala Tips / Either (3) - getOrElse</title><content type='html'>&lt;div&gt;&lt;p&gt;Eitherから値を取り出すイディオムです。&lt;/p&gt;&lt;p&gt;EitherをOption的な成功/失敗文脈で使う方法について考えています。右側が成功文脈、左側が失敗文脈としています。&lt;/p&gt;&lt;p&gt;Eitherの場合も、Optionと同様に値を取り出す処理として以下の2つのコーディングパターンがあります。&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Either[A, B]からEither[A, C]に変換&lt;/li&gt;&lt;li&gt;Eigher[A, B]からCに変換&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;ここまではEither[A, B]からEither[A, C]への変換についてみてきました。今回はEither[A, B]からCへの変換について考えます。&lt;/p&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;条件&lt;/th&gt;&lt;th&gt;結果&lt;/th&gt;&lt;th&gt;演算&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Either[A, B]がRight[A, B]&lt;/td&gt;&lt;td&gt;C&lt;/td&gt;&lt;td&gt;BからCを計算&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Either[A, B]がLeft[A, B]&lt;/td&gt;&lt;td&gt;C&lt;/td&gt;&lt;td&gt;デフォルト値&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;Either[A, B]がRight[A, B]の場合は、この値からCを計算しますが、Left[A, B]の場合はあらかじめ用意しているデフォルト値を返します。&lt;/p&gt;&lt;p&gt;以下では、Either[Exception, Int]からStringへの変換を例に考えてみます。Either[Exception, Int]がLeft[Exception]の場合はデフォルト値として空文字列「&amp;quot;&amp;quot;」を返すことにします。&lt;/p&gt;&lt;p&gt;(&lt;a href="http://modegramming.blogspot.com/2012/01/scala-tipsoption.html"&gt;分類の基準&lt;/a&gt;)&lt;/p&gt;&lt;div&gt;&lt;h4&gt;Java風&lt;/h4&gt;&lt;p&gt;if式でEither#isRightを使って右側の値の有無を判定します。デフォルト値の「&amp;quot;&amp;quot;」はelse句で指定します。isRightメソッドとgetメソッドが泣き別れになっているのがあまりよい感触ではありません。&lt;/p&gt;&lt;pre name="code" class="java"&gt;def f(a: Either[Exception, Int]): String = {&lt;br /&gt;  if (a.isRight) a.right.get.toString&lt;br /&gt;  else &amp;quot;&amp;quot;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;Scala風&lt;/h4&gt;&lt;p&gt;match式を使うと以下のようになります。こちらの方が綺麗です。&lt;/p&gt;&lt;pre name="code" class="java"&gt;def f(a: Either[Exception, Int]): String = {&lt;br /&gt;  a match {&lt;br /&gt;    case Right(b) =&amp;gt; b.toString&lt;br /&gt;    case Left(_) =&amp;gt; &amp;quot;&amp;quot;&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;Scala&lt;/h4&gt;&lt;p&gt;EitherでMonadic演算をしたい場合にはright(またはleft)メソッドでRightProjection(またはLeftProjection)を取得し、これに対してmapメソッドやflatMapメソッドを適用します。EitherとRightProjection/LeftProjectionの組合せでモナド的な動作をします。&lt;/p&gt;&lt;p&gt;以下ではEitherからrightメソッドでRightProjectionを取り出しmap適用、mapの結果のEitherからrightメソッドでRightProjectionを取り出しgetOrElseで値を取り出す、という形でEither→right→RightProjectionの連鎖で処理を進めています。&lt;/p&gt;&lt;p&gt;最後に、flatMapの結果のEitherからrightメソッドでRightProjectionを取り出しgetOrElseで値を取り出します。&lt;/p&gt;&lt;pre name="code" class="java"&gt;def f(a: Either[Exception, Int]): String = {&lt;br /&gt;  a.right.map(_.toString).right getOrElse &amp;quot;&amp;quot;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div&gt;&lt;h5&gt;Optionに変換&lt;/h5&gt;&lt;p&gt;最終的に値を取り出す場合、左側に保持しているエラー情報は捨てることになります。この場合には、エラー情報(Exception)を最初の段階で捨ててしまい、エラーか否かという情報のみを伝搬しても得られる結果は同じです。&lt;/p&gt;&lt;p&gt;そこで、最初の段階でRightProjectionのtoOptionメソッドでOptionに変換し、Optionに対してMonadic演算を行うようにします。&lt;/p&gt;&lt;p&gt;以下ではOptionに変換後、mapメソッドとgetOrElseメソッドの合わせ技で値を取得しています。&lt;/p&gt;&lt;pre name="code" class="java"&gt;def f(a: Either[Exception, Int]): String = {&lt;br /&gt;  a.right.toOption.map(_.toString) getOrElse &amp;quot;&amp;quot;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;Scalaz&lt;/h4&gt;&lt;p&gt;ScalazではEitherが右側を成功文脈とする成功/失敗の文脈としても動作するので、Either#rightメソッドでRightProjectionを取得しなくてもEitherに対して直接mapメソッドを適用することができます。ただし、ScalazでもEitherにgetOrElseメソッドはないので、rightメソッドでRightProjectionを取得する必要があります。このためScala版と比べてそれほど違いは出てきません。&lt;/p&gt;&lt;pre name="code" class="java"&gt;def f(a: Either[Exception, Int]): String = {&lt;br /&gt;  a.map(_.toString).right getOrElse &amp;quot;&amp;quot;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div&gt;&lt;h5&gt;Optionに変換&lt;/h5&gt;&lt;p&gt;ScalazでもEitherにtoOptionメソッドは追加されないのでrightメソッドで得られるRightProjectionのtoOptionメソッドを用いてOptionに変換します。&lt;/p&gt;&lt;pre name="code" class="java"&gt;def f(a: Either[Exception, Int]): String = {&lt;br /&gt;  a.right.toOption.map(_.toString) | &amp;quot;&amp;quot;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Scalazでは、Optionに対して色々な機能拡張を行っているので、Optionに変換すればいろいろな技を使うことが可能になります。ここでは「|」メソッドで値を取り出しています。&lt;/p&gt;&lt;p&gt;また、以下のようにデフォルト値が&lt;a href="http://modegramming.blogspot.com/2012/02/scala-tips-option-8.html"&gt;モノイドの単位元と同じ場合にはorZeroメソッド&lt;/a&gt;を使うこともできます。&lt;/p&gt;&lt;pre name="code" class="java"&gt;def f(a: Either[Exception, Int]): String = {&lt;br /&gt;  a.right.toOption.map(_.toString) orZero&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;ノート&lt;/h4&gt;&lt;p&gt;Eitherは、Optionに比べるとかなり扱いにくいオブジェクトです。Scala標準クラスライブラリでは、あくまでも直和、選択を表現するためのオブジェクトであり、典型的な使い方である成功/失敗文脈を扱うのに便利な機能(右側を特別扱いする関数など)が用意されていません。またEitherそのものはOptionのようなモナドでもありませんし、今の所利用頻度がそれほど多くないためか、その他Eitherを取り回す時に便利なユーティリティ機能が少ないので、Optionのような使いやすさにはなりません。&lt;/p&gt;&lt;p&gt;Scalazでも、多少状況は緩和されますが扱いにくいオブジェクトであることは変わりません。&lt;/p&gt;&lt;p&gt;Eitherの文脈を維持する必要がある場合は仕方ありませんが、今回のようにエラー情報そのものは捨ててもよい場合には、最初の段階で計算文脈をEither(エラー情報を保持する成功/失敗文脈)からOption(エラー情報を保持しない成功/失敗文脈)に切り替えるのが有力なテクニックです。&lt;/p&gt;&lt;p&gt;計算文脈の複雑度が低くなるのでプログラミングが扱うべき事項も小さくなります。また、OptionはScalaでもScalazでも、Eitherに比べると機能が豊富でいろいろな技が使えるので、プログラミングの選択肢が広がります。&lt;/p&gt;&lt;p&gt;エラー情報を保持しつつ、成功/失敗の計算文脈でプログラミングを行う場合は、ScalazのValidationが有力な選択肢になります。ValidationはEitherに続けて取り上げる予定です。&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;諸元&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Scala 2.9.1&lt;/li&gt;&lt;li&gt;Scalaz 6.0.3&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7964484936470829118-7884899701006454175?l=modegramming.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://modegramming.blogspot.com/feeds/7884899701006454175/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://modegramming.blogspot.com/2012/02/scala-tips-either-3-getorelse.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/7884899701006454175'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/7884899701006454175'/><link rel='alternate' type='text/html' href='http://modegramming.blogspot.com/2012/02/scala-tips-either-3-getorelse.html' title='Scala Tips / Either (3) - getOrElse'/><author><name>asami</name><uri>http://www.blogger.com/profile/12083671403528595185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_4HtJQwbXqEY/S4sSwhKz5fI/AAAAAAAAAFs/IvXW6ca5RGE/S220/profile.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7964484936470829118.post-3583795999577505928</id><published>2012-02-14T08:00:00.000+09:00</published><updated>2012-02-14T09:45:42.826+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tips'/><category scheme='http://www.blogger.com/atom/ns#' term='scalaz'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>Scala Tips / Either (2) - flatMap</title><content type='html'>&lt;div&gt;&lt;p&gt;Eitherを成功/失敗の文脈で使用する方法のイディオムです。&lt;/p&gt;&lt;p&gt;前回はEitherをOptionと同じ成功/失敗の文脈で使用する方法について見てきました。&lt;/p&gt;&lt;p&gt;これは以下の演算になりますが、ちょうど、Optionでいうと「&lt;a href="http://modegramming.blogspot.com/2012/01/scala-tips-option-3.html"&gt; Option (3) - map&lt;/a&gt; 」に相当する処理です。&lt;/p&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;条件&lt;/th&gt;&lt;th&gt;結果&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Either[A, B]がRight[A, B]&lt;/td&gt;&lt;td&gt;Right[A, C]&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Either[A, B]がLeft[A, B]&lt;/td&gt;&lt;td&gt;Left[A, C]&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;今回は以下の処理、アプリケーションの意図で成功の文脈を失敗の文脈に切り替えるためのMonadic演算についてみていきます。Optionでいうと「&lt;a href="http://modegramming.blogspot.com/2012/02/scala-tips-option-6.html"&gt;Option (6) - flatMap&lt;/a&gt; 」に相当する処理になります。&lt;/p&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;条件&lt;/th&gt;&lt;th&gt;結果&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Either[A, B]のRight[A, B]に有効な値が入っている&lt;/td&gt;&lt;td&gt;Right[A, C]&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Either[A, B]のRight[A, B]に無効な値が入っている&lt;/td&gt;&lt;td&gt;Left[A, C]&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Either[A, B]がLeft[A, B]&lt;/td&gt;&lt;td&gt;Left[A, C]&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;大枠ではB→Cの演算を行いたいわけですが、これをEither[A, B→C]の文脈の上で行います。この時、Either[A, B]がRight[A, B]であっても「B」が無効な値である場合には、Left[A, C]にすることで、成功の文脈から失敗の文脈へ切り替えます。&lt;/p&gt;&lt;p&gt;以下では、Either[Exception, Int]からEither[Exception, String]への変換を例に考えてみます。ただし、Intは0以上のものが有効という条件を追加します。Either(Right)に入っているIntが0以上の場合、Right[Exception, String]が処理結果となります。一方、0未満の場合は無効となりLeft[Exception, String]が処理結果となります。&lt;/p&gt;&lt;div&gt;&lt;h4&gt;Java風&lt;/h4&gt;&lt;p&gt;if式でEither#isRightメソッドを使ってLeftとRightの判定をして、処理を切り分ける事ができます。&lt;/p&gt;&lt;pre name="code" class="java"&gt;def f(a: Either[Exception, Int]): Either[Exception, String] = {&lt;br /&gt;  if (a.isRight) {&lt;br /&gt;    if (a.right.get &amp;gt;= 0) {&lt;br /&gt;      Right(a.right.get.toString)&lt;br /&gt;    } else {&lt;br /&gt;      Left(new IllegalArgumentException(&amp;quot;less than 0&amp;quot;))&lt;br /&gt;    }&lt;br /&gt;  } else {&lt;br /&gt;    a.asInstanceOf[Either[Exception, String]]&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;Scala風&lt;/h4&gt;&lt;p&gt;match式を使うとLeftとRightのパターンマッチングで綺麗に書くことができます。ただし、Scala的にはLeft(b)の場合はLeft(b)というロジックを書くのが悔しい。&lt;/p&gt;&lt;pre name="code" class="java"&gt;def f(a: Either[Exception, Int]): Either[Exception, String] = {&lt;br /&gt;  a match {&lt;br /&gt;    case Right(b) if (b &amp;gt;= 0) =&amp;gt; Right(b.toString)&lt;br /&gt;    case Right(_) =&amp;gt; Left(new IllegalArgumentException(&amp;quot;less than 0&amp;quot;))&lt;br /&gt;    case Left(b) =&amp;gt; Left(b)&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;Scala&lt;/h4&gt;&lt;p&gt;Eitherのrightメソッドで得られるRightProjectionがモナドっぽい動きをするので、flatMapメソッドを使ってMonadicプログラミングします。flatMapメソッドでは、Int値が0以上である場合は有効な値なのでStringに変換する演算を行い結果をRightオブジェクトに詰めて返します。一方、Int値が0未満の場合は、無効な値なので成功の文脈から失敗の文脈への切り替えとして、LeftオブジェクトにIllegalArgumentExceptionを詰めて返します。&lt;/p&gt;&lt;pre name="code" class="java"&gt;def f(a: Either[Exception, Int]): Either[Exception, String] = {&lt;br /&gt;  a.right.flatMap { b =&amp;gt;&lt;br /&gt;    if (b &amp;gt;= 0) Right(b.toString)&lt;br /&gt;    else Left(new IllegalArgumentException(&amp;quot;less than 0&amp;quot;))&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;Scalaz&lt;/h4&gt;&lt;p&gt;Scalazを使うと、Eitherが右側を成功の文脈として動作するモナドに拡張されるので、これを利用したプログラミングが可能です。やはりflatMapメソッドを使います。また、LeftとRightの生成をleftメソッド、rightメソッドで簡潔に記述できるようになります。&lt;/p&gt;&lt;pre name="code" class="java"&gt;def f(a: Either[Exception, Int]): Either[Exception, String] = {&lt;br /&gt;  a.flatMap { b =&amp;gt;&lt;br /&gt;    if (b &amp;gt;= 0) b.toString.right&lt;br /&gt;    else new IllegalArgumentException(&amp;quot;less than 0&amp;quot;).left&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;ノート&lt;/h4&gt;&lt;p&gt;前回は、Eitherのrightメソッドで返ってくるRightProjectionを使えばMonadic演算が可能なことを説明しました。&lt;/p&gt;&lt;p&gt;RightProjectionを使って、Optionで使用したwithFilter, collect, flatMap, for式といった技が駆使できると嬉しいのですが、残念ながらそうはなっていません。以下の理由により、この中で使える/使って便利なのはflatMapのみとなります。&lt;/p&gt;&lt;p&gt;collectメソッドはRightProjectionにそもそも機能がありません。&lt;/p&gt;&lt;p&gt;withFilterメソッドやfilterメソッドはEither[A, B]ではなくOption[Either[A, B]]を返すので、Optionのハンドリングが余分に必要になります。これは、それなりのコードになってしまうので、それよりflatMapメソッドを使ったほうが簡潔です。&lt;/p&gt;&lt;p&gt;for式は内部的にwithFilterメソッドを使っているので、やはり使えません。&lt;/p&gt;&lt;p&gt;以上の理由で、Eitherに対しては他の機能のことは考えずに、文脈の切り替えはflatMapメソッド一本で考えていくのが得策です。&lt;/p&gt;&lt;p&gt;Scalazの場合も事情は同じで(Left/RightProjectionではなく)EitherのflatMapメソッドを使って処理を記述することになります。&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;追記 (2012-02-14)&lt;/h4&gt;&lt;div&gt;&lt;p&gt;ひなたねこさんのツイートでよりScalazらしい書き方が判明したので補足します。&lt;/p&gt;&lt;p&gt;以下はEither[Exception, Int]の生成にBooleanのeitherメソッドを使ったバージョンです。Right(…)、….rightやLeft(…)、….leftが出てこないので、より簡潔でScalazらしいですね。&lt;/p&gt;&lt;pre name="code" class="java"&gt;def f(a: Either[Exception, Int]): Either[Exception, String] = {&lt;br /&gt;  a.flatMap { b =&amp;gt;&lt;br /&gt;    !(b &amp;gt;= 0) either {&lt;br /&gt;      new IllegalArgumentException(&amp;quot;less than 0&amp;quot;)&lt;br /&gt;    } or b.toString&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;またScala版の記述をleftメソッド、rightメソッドを使うものに更新しました。&lt;br /&gt;&lt;/div&gt;&lt;h4&gt;諸元&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Scala 2.9.1&lt;/li&gt;&lt;li&gt;Scalaz 6.0.3&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7964484936470829118-3583795999577505928?l=modegramming.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://modegramming.blogspot.com/feeds/3583795999577505928/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://modegramming.blogspot.com/2012/02/scala-tips-either-2-flatmap.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/3583795999577505928'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/3583795999577505928'/><link rel='alternate' type='text/html' href='http://modegramming.blogspot.com/2012/02/scala-tips-either-2-flatmap.html' title='Scala Tips / Either (2) - flatMap'/><author><name>asami</name><uri>http://www.blogger.com/profile/12083671403528595185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_4HtJQwbXqEY/S4sSwhKz5fI/AAAAAAAAAFs/IvXW6ca5RGE/S220/profile.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7964484936470829118.post-430805157679079224</id><published>2012-02-13T08:00:00.000+09:00</published><updated>2012-02-13T15:56:26.439+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tips'/><category scheme='http://www.blogger.com/atom/ns#' term='scalaz'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>Scala Tips / Either</title><content type='html'>&lt;div&gt;&lt;p&gt;Eitherは直和(disjoint union)を表現するオブジェクトです。数学的な意味は&lt;a href="http://ja.wikipedia.org/wiki/%E7%9B%B4%E5%92%8C"&gt;こちら&lt;/a&gt;を参照してください。&lt;/p&gt;&lt;p&gt;直和は、プログラミング的な観点でざっくりというと二つの種類の値のどちらかを選択する(choice)という意味です。&lt;/p&gt;&lt;p&gt;Eitherでは、2つの種類の値のことをそれぞれleftとrightと呼んでいます。以下ではleftの値を「左側」、rightの値を「右側」と表現することにします。&lt;/p&gt;&lt;p&gt;Eitherの典型的な使い方は、関数の成功と失敗を、成功時の返却値、失敗時の返却値と合わせて通知するというものです。EitherのサブクラスはRightとLeftの2つで、成功の場合はRight、失敗の場合はLeftを使う慣習になっています。右側のRightを成功の用途に使うという慣習は、いうまでもなく「Right=正しい」という英語の意味にかけています。&lt;/p&gt;&lt;p&gt;Eitherを使ってOptionと同様の成功/失敗の計算文脈上でのMonadicプログラミングをすることが可能です。&lt;/p&gt;&lt;p&gt;今回は&lt;a href="http://modegramming.blogspot.com/2012/01/scala-tips-option-3.html"&gt;Option(3)&lt;/a&gt;の課題のEither版を考えてみます。&lt;/p&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;条件&lt;/th&gt;&lt;th&gt;結果&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Either[A, B]がRight[A, B]&lt;/td&gt;&lt;td&gt;Right[A, C]&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Either[A, B]がLeft[A, B]&lt;/td&gt;&lt;td&gt;Left[A, C]&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;大枠ではB→Cの演算を行いたいわけですが、これをEither[A, B→C]の文脈の上で行うわけです。&lt;/p&gt;&lt;p&gt;以下で左側(失敗側)にException、右側(成功側)にIntを持つをEither、つまりEither[Exception, Int]をEither[Exception, String]に変換するプログラムを考えます。&lt;/p&gt;&lt;p&gt;(&lt;a href="http://modegramming.blogspot.com/2012/01/scala-tipsoption.html"&gt;分類の基準&lt;/a&gt;)&lt;/p&gt;&lt;div&gt;&lt;h4&gt;Java風&lt;/h4&gt;&lt;p&gt;if式でEither#isRightメソッドを使ってLeftとRightの判定をして、処理を切り分ける事ができます。&lt;/p&gt;&lt;pre name="code" class="java"&gt;def f(a: Either[Exception, Int]): Either[Exception, String] = {&lt;br /&gt;  if (a.isRight) {&lt;br /&gt;    Right(a.right.get.toString)&lt;br /&gt;  } else {&lt;br /&gt;    a.asInstanceOf[Either[Exception, String]]&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;Scala風&lt;/h4&gt;&lt;p&gt;match式を使うとLeftとRightのパターンマッチングで綺麗に書くことができます。ただし、Scala的にはLeft(b)の場合はLeft(b)というロジックを書くのが悔しい。&lt;/p&gt;&lt;pre name="code" class="java"&gt;def f(a: Either[Exception, Int]): Either[Exception, String] = {&lt;br /&gt;  a match {&lt;br /&gt;    case Right(b) =&amp;gt; Right(b.toString)&lt;br /&gt;    case Left(b) =&amp;gt; Left(b)&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p/&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;Scala&lt;/h4&gt;&lt;p&gt;Eitherのrightメソッドで得られるRightProjectionがモナドっぽい動きをするので、これを使ってMonadicプログラミングします。&lt;/p&gt;&lt;pre name="code" class="java"&gt;def f(a: Either[Exception, Int]): Either[Exception, String] = {&lt;br /&gt;  a.right.map(_.toString)&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;RightProjectionそのものはモナドではなく、EitherとRightProjectionを合わせて一つのモナド、というような動きになります。たとえば、mapメソッドを繋げる場合は以下のようになります。&lt;/p&gt;&lt;pre name="code" class="java"&gt;a.right.map(_.toString).right.map(_.toInt)&lt;/pre&gt;&lt;p/&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;Scalaz&lt;/h4&gt;&lt;p&gt;Scalazを使うと、Eitherが右画はを成功の文脈として動作するモナドに拡張されるので、これを利用したプログラミングが可能です。&lt;/p&gt;&lt;pre name="code" class="java"&gt;def f(a: Either[Exception, Int]): Either[Exception, String] = {&lt;br /&gt;  a.map(_.toString)&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;ScalazではEitherが、エラー情報付きのOption的な機能を持つオブジェクト/モナドになるわけです。&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;ノート&lt;/h4&gt;&lt;p&gt;ScalaのEitherはモナドではないので、Monadicな演算、つまり計算文脈上で値を操作する演算をするためにはちょっとコツが要ります。&lt;/p&gt;&lt;p&gt;Eitherのleftメソッド、rightメソッドで得られるLeftProjection、RightProjectionがモナド的な動きをします。EitherとLeftProjection、RightProjectionを合わせて一つのモナドという使い方になります。&lt;/p&gt;&lt;p&gt;Eitherでは左側と右側を公平に扱っています。左側を主にMonadic演算をする場合は右側は自動的に引き継がれる、逆に右側を主にMonadic演算をする場合は左側は自動的に生き継がれる、という動きになります。左側が主の場合は、leftメソッドで得られるLeftProjection、右側が主の場合は、rightメソッドで得られるRightProjectionを使うわけです。直和を表現するという趣旨からは妥当な仕様です。&lt;/p&gt;&lt;p&gt;しかし、Eitherの典型的な使い方である成功/失敗の文脈の用途では、右側を成功の文脈とするのが慣習となっているため、Either自身が右側を成功の文脈とするモナドである方が使い勝手が良くなります。&lt;/p&gt;&lt;p&gt;Scalazを使うと、まさにこのEitherの右側を成功の文脈とするモナドの機能が付加されます。&lt;/p&gt;&lt;p&gt;日々のプログラミングでは、Option的な成功/失敗の文脈が、Eitherの主たる用途になるのでScalazの拡張を利用するとよいでしょう。&lt;/p&gt;&lt;p&gt;Scala基本クラスの提供する左側と右側が平等に扱われるMonadic演算も、応用にハマれば面白い使い方ができそうです。&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;追記 (2012-02-13)&lt;/h4&gt;よい表現を思いついたので更新しました。&lt;br /&gt;&lt;ul&gt;&lt;li&gt;二つの種類の値のどちらかを取る→二つの種類の値どちらかを選択する(choice)&lt;br /&gt;&lt;/ul&gt;&lt;h4&gt;諸元&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Scala 2.9.1&lt;/li&gt;&lt;li&gt;Scalaz 6.0.3&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7964484936470829118-430805157679079224?l=modegramming.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://modegramming.blogspot.com/feeds/430805157679079224/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://modegramming.blogspot.com/2012/02/scala-tips-either.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/430805157679079224'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/430805157679079224'/><link rel='alternate' type='text/html' href='http://modegramming.blogspot.com/2012/02/scala-tips-either.html' title='Scala Tips / Either'/><author><name>asami</name><uri>http://www.blogger.com/profile/12083671403528595185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_4HtJQwbXqEY/S4sSwhKz5fI/AAAAAAAAAFs/IvXW6ca5RGE/S220/profile.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7964484936470829118.post-8177869136262093393</id><published>2012-02-12T09:00:00.000+09:00</published><updated>2012-02-12T09:00:01.376+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='smartdox'/><title type='text'>SmartDox 0.2.2</title><content type='html'>&lt;div&gt;&lt;p&gt;SmartDox 0.2.2をリリースしました。&lt;/p&gt;&lt;p&gt;本バージョンはorg-modeの解析方法を改良しました。&lt;/p&gt;&lt;div&gt;&lt;h4&gt;機能&lt;/h4&gt;&lt;p&gt;SmartDox 0.2.2では以下のオプションを提供しています。&lt;/p&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;オプション&lt;/th&gt;&lt;th&gt;機能&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;-html5&lt;/td&gt;&lt;td&gt;HTML5生成(試験的)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;-html4&lt;/td&gt;&lt;td&gt;HTML4生成&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;-html3&lt;/td&gt;&lt;td&gt;HTML3生成&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;-plain&lt;/td&gt;&lt;td&gt;プレインテキスト生成&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;-pdf&lt;/td&gt;&lt;td&gt;PDF生成&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;-latex&lt;/td&gt;&lt;td&gt;LaTeX生成&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;-blogger&lt;/td&gt;&lt;td&gt;Blogger用のHTML生成&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;基本的に&lt;a href="http://modegramming.blogspot.com/2012/01/smartdox-021.html"&gt;SmartDox 0.2.1&lt;/a&gt;と同じです。org-modeの解析方法を改良しました。&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;インストール&lt;/h4&gt;&lt;p&gt;プログラムの配布は、Scalaで最近注目されているconscriptを使っています。conscriptのインストール方法は以下のページに詳しいです。&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://blog.twiwt.org/e/58baf0"&gt;conscript - Scala で作られたソフトウェアをインストールするためのツール&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Linux, Macであれば、以下のようにすればインストール完了です。&lt;/p&gt;&lt;pre class="console"&gt;$ curl https://raw.github.com/n8han/conscript/master/setup.sh | sh&lt;/pre&gt;&lt;p&gt;conscriptをインストールした後、以下のようにしてSmartDoxをインストールします。&lt;/p&gt;&lt;pre class="console"&gt;$ cs asami/dox&lt;/pre&gt;&lt;p&gt;以下の2つのコマンドがインストールされます。&lt;/p&gt;&lt;dl&gt;&lt;dt&gt;dox&lt;/dt&gt;&lt;dd&gt;SmartDoxコマンド&lt;/dd&gt;&lt;dt&gt;sdoc&lt;/dt&gt;&lt;dd&gt;SmartDocコマンド(互換用)&lt;/dd&gt;&lt;/dl&gt;&lt;div&gt;&lt;h5&gt;依存プロダクト&lt;/h5&gt;&lt;p&gt;SmartDoxでは、以下のプロダクトに依存しています。&lt;/p&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;プロダクト&lt;/th&gt;&lt;th&gt;使用する機能&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;a href="http://www.latex-project.org/"&gt;LaTeX&lt;/a&gt;&lt;/td&gt;&lt;td&gt;PDF生成&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href="http://www.graphviz.org/"&gt;Graphviz&lt;/a&gt;&lt;/td&gt;&lt;td&gt;画像生成&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href="http://ditaa.sourceforge.net/"&gt;Ditaa&lt;/a&gt;&lt;/td&gt;&lt;td&gt;画像生成&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;プロダクトに依存する機能を使わない場合は必要ありません。&lt;/p&gt;&lt;div&gt;&lt;h6&gt;LaTeX&lt;/h6&gt;&lt;p&gt;platexコマンドとdvipdfmxコマンドが実行可能になっていれば基本的にはOKです。&lt;/p&gt;&lt;p&gt;Mac OS上でmacportsを使ってインストールしたLaTeXで動作確認しています。他の環境の場合、スタイルファイルなどがない可能性があります。&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;h6&gt;Graphviz&lt;/h6&gt;&lt;p&gt;dotコマンドが実行可能になっていればOKです。&lt;/p&gt;&lt;p&gt;Mac OS上でmacportsを使ってインストールしたGraphvizで動作確認しています。&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;h6&gt;Ditaa&lt;/h6&gt;&lt;p&gt;ditaaコマンドが実行可能になっているか、&lt;i&gt;&lt;/i&gt;opt&lt;i&gt;&lt;/i&gt;local&lt;i&gt;&lt;/i&gt;share&lt;i&gt;&lt;/i&gt;java&lt;i&gt;&lt;/i&gt;ditaa0&lt;u&gt;&lt;/u&gt;9.jarのJarファイルが存在していればOKです。&lt;/p&gt;&lt;p&gt;Mac OS上でmacportsを使ってDitaaをインストールすると、&lt;i&gt;&lt;/i&gt;opt&lt;i&gt;&lt;/i&gt;local&lt;i&gt;&lt;/i&gt;share&lt;i&gt;&lt;/i&gt;java&lt;i&gt;&lt;/i&gt;ditaa0&lt;u&gt;&lt;/u&gt;9.jarに配置されます。このditaa0&lt;u&gt;&lt;/u&gt;9.jarを決め打ちで使用しています。(いずれパラメタで指定可能にする予定です。)&lt;/p&gt;&lt;p&gt;それ以外の環境では、シェルスクリプトなどでditaaコマンド(インストールされているJarファイルを呼び出す)を作成してください。&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;使い方&lt;/h4&gt;&lt;p&gt;まだマニュアルがないので、文書フォーマットは &lt;a href="http://orgmode.org/ja/index.html"&gt;org-mode&lt;/a&gt;を参考にしてください。あまり難しい文法を使わなければ大体大丈夫だと思います。&lt;/p&gt;&lt;p&gt;org-mode形式で作成した文書から以下のようにしてHTMLやPDF、プレインテキストに変換してください。&lt;/p&gt;&lt;pre class="console"&gt;$ dox -html4 mydoc.dox&lt;br /&gt;$ dox -pdf mydoc.dox&lt;br /&gt;$ dox -plain mydoc.dox&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;サンプル&lt;/h4&gt;&lt;p&gt;SmartDoxでは以下のようなorg-mode文書が扱えます。&lt;/p&gt;&lt;pre name="code" class="java"&gt;#+title: SmartDoxサンプル&lt;br /&gt;#+author: 浅海&lt;br /&gt;#+date: 2012年2月12日&lt;br /&gt;&lt;br /&gt;* 文章&lt;br /&gt;&lt;br /&gt;これは *SmartDox* の文章です。&lt;br /&gt;&lt;br /&gt;- SmartDoxのコンセプトは(org-mode＋html5)／2&lt;br /&gt;- HTMLに加えてPDFやプレインテキストを生成することができます。&lt;br /&gt;- GraphvizやDitaaの画像を生成して埋め込むことができます。&lt;br /&gt;&lt;br /&gt;* 表&lt;br /&gt;&lt;br /&gt;| オプション | 機能                 |&lt;br /&gt;|------------+----------------------|&lt;br /&gt;| -html5     | HTML5生成(試験的)    |&lt;br /&gt;| -html4     | HTML4生成            |&lt;br /&gt;| -html3     | HTML3生成            |&lt;br /&gt;| -plain     | プレインテキスト生成 |&lt;br /&gt;| -pdf       | PDF生成              |&lt;br /&gt;| -latex     | LaTeX生成            |&lt;br /&gt;| -blogger   | Blogger用のHTML生成  |&lt;br /&gt;&lt;br /&gt;* 画像&lt;br /&gt;&lt;br /&gt;** graphviz&lt;br /&gt;&lt;br /&gt;[[http://www.graphviz.org/][Graphviz]] の図を直接書くことができます。&lt;br /&gt;&lt;br /&gt;#+begin_dot images/dot_example.png -Tpng&lt;br /&gt;digraph G {&lt;br /&gt;  Hello-&amp;gt;World&lt;br /&gt;}&lt;br /&gt;#+end_dot&lt;br /&gt;&lt;br /&gt;** ditaa&lt;br /&gt;&lt;br /&gt;[[http://ditaa.sourceforge.net/][Ditaa]] の図を直接書くことができます。&lt;br /&gt;&lt;br /&gt;#+begin_ditaa images/ditaa_example.png&lt;br /&gt;+--------+   +-------+    +-------+&lt;br /&gt;|        | --+ ditaa +--&amp;gt; |       |&lt;br /&gt;|  Text  |   +-------+    |diagram|&lt;br /&gt;|Document|   |!magic!|    |       |&lt;br /&gt;|     {d}|   |       |    |       |&lt;br /&gt;+---+----+   +-------+    +-------+&lt;br /&gt;    :                         ^&lt;br /&gt;    |       Lots of work      |&lt;br /&gt;    +-------------------------+&lt;br /&gt;#+end_ditaa&lt;br /&gt;&lt;br /&gt;** SimpleModeler&lt;br /&gt;&lt;br /&gt;SimpleModelerを使ってCSVでクラス図を&lt;br /&gt;書くことができます。&lt;br /&gt;&lt;br /&gt;#+begin_sm_csv images/sm_csv_simplemodel.png&lt;br /&gt;#actor&lt;br /&gt;顧客&lt;br /&gt;個人顧客,,,,,顧客&lt;br /&gt;法人顧客,,,,,顧客&lt;br /&gt;#resource&lt;br /&gt;商品,商品名,,商品区分(第1類;第2類;第3類)&lt;br /&gt;#event&lt;br /&gt;購入する,,顧客;商品&lt;br /&gt;#+end_sm_csv&lt;br /&gt;&lt;/pre&gt;&lt;div&gt;&lt;h5&gt;PDF&lt;/h5&gt;&lt;p&gt;PDFの生成は以下のようにして行います。PDFの生成時に画像の生成も自動的に行いPDF内に埋め込まれます。&lt;/p&gt;&lt;pre class="console"&gt;$ dox -plain sample.dox&lt;/pre&gt;&lt;p&gt;3ページのPDFが生成されます。2ページ目は以下のように表や図が記述されています。&lt;/p&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-RLEhUA4o6zA/TzbwmBf_9OI/AAAAAAAAASU/VGrkC1YkEnE/s1600/page2.png" imageanchor="1" style=""&gt;&lt;img border="0" height="400" width="381" src="http://4.bp.blogspot.com/-RLEhUA4o6zA/TzbwmBf_9OI/AAAAAAAAASU/VGrkC1YkEnE/s400/page2.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;1ページ目はタイトル、3ページ目はditaaとSimpleModeleの図です。&lt;/p&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-5HVFDIWzhVw/TzbwuD-RkPI/AAAAAAAAASg/11I1vpc1XHA/s1600/page1.png" imageanchor="1" style=""&gt;&lt;img border="0" height="400" width="381" src="http://2.bp.blogspot.com/-5HVFDIWzhVw/TzbwuD-RkPI/AAAAAAAAASg/11I1vpc1XHA/s400/page1.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-FCdP4aay6eU/TzbwyuKN0uI/AAAAAAAAASs/5bZd3P3taLg/s1600/page3.png" imageanchor="1" style=""&gt;&lt;img border="0" height="400" width="381" src="http://4.bp.blogspot.com/-FCdP4aay6eU/TzbwyuKN0uI/AAAAAAAAASs/5bZd3P3taLg/s400/page3.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;h5&gt;プレインテキスト&lt;/h5&gt;&lt;p&gt;ブラウザでは崩れて見えますが、等幅フォントを使えば表やタイトル下の下線も正しくレイアウトされます。&lt;/p&gt;&lt;pre name="code" class="java"&gt;SmartDoxサンプル&lt;br /&gt;                           ━━━━━━━━&lt;br /&gt;&lt;br /&gt;                            2012年2月12日&lt;br /&gt;                                 浅海&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;目次&lt;br /&gt;──&lt;br /&gt;&lt;br /&gt;  1 文章&lt;br /&gt;  2 表&lt;br /&gt;  3 画像&lt;br /&gt;    3.1 graphviz&lt;br /&gt;    3.2 ditaa&lt;br /&gt;    3.3 SimpleModeler&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;1 文章&lt;br /&gt;───&lt;br /&gt;&lt;br /&gt;  これは SmartDox の文章です。&lt;br /&gt;&lt;br /&gt;    - SmartDoxのコンセプトは(org-mode＋html5)／2&lt;br /&gt;    - HTMLに加えてPDFやプレインテキストを生成することができます。&lt;br /&gt;    - GraphvizやDitaaの画像を生成して埋め込むことができます。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;2 表&lt;br /&gt;──&lt;br /&gt;&lt;br /&gt;┏━━━━━┯━━━━━━━━━━┓&lt;br /&gt;┃オプション│        機能        ┃&lt;br /&gt;┣━━━━━┿━━━━━━━━━━┫&lt;br /&gt;┃-html5    │HTML5生成(試験的)   ┃&lt;br /&gt;┠─────┼──────────┨&lt;br /&gt;┃-html4    │HTML4生成           ┃&lt;br /&gt;┠─────┼──────────┨&lt;br /&gt;┃-html3    │HTML3生成           ┃&lt;br /&gt;┠─────┼──────────┨&lt;br /&gt;┃-plain    │プレインテキスト生成┃&lt;br /&gt;┠─────┼──────────┨&lt;br /&gt;┃-pdf      │PDF生成             ┃&lt;br /&gt;┠─────┼──────────┨&lt;br /&gt;┃-latex    │LaTeX生成           ┃&lt;br /&gt;┠─────┼──────────┨&lt;br /&gt;┃-blogger  │Blogger用のHTML生成 ┃&lt;br /&gt;┗━━━━━┷━━━━━━━━━━┛&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;3 画像&lt;br /&gt;───&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;3.1 graphviz&lt;br /&gt;──────&lt;br /&gt;&lt;br /&gt;  Graphviz&amp;lt;http://www.graphviz.org/&amp;gt; の図を直接書くことができます。&lt;br /&gt;  &amp;lt;images/dot_example.png&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;3.2 ditaa&lt;br /&gt;─────&lt;br /&gt;&lt;br /&gt;  Ditaa&amp;lt;http://ditaa.sourceforge.net/&amp;gt; の図を直接書くことができます。&lt;br /&gt;  &amp;lt;images/ditaa_example.png&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;3.3 SimpleModeler&lt;br /&gt;─────────&lt;br /&gt;&lt;br /&gt;  SimpleModelerを使ってCSVでクラス図を書くことができます。&lt;br /&gt;  &amp;lt;images/sm_csv_simplemodel.png&amp;gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7964484936470829118-8177869136262093393?l=modegramming.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://modegramming.blogspot.com/feeds/8177869136262093393/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://modegramming.blogspot.com/2012/02/smartdox-022.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/8177869136262093393'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/8177869136262093393'/><link rel='alternate' type='text/html' href='http://modegramming.blogspot.com/2012/02/smartdox-022.html' title='SmartDox 0.2.2'/><author><name>asami</name><uri>http://www.blogger.com/profile/12083671403528595185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_4HtJQwbXqEY/S4sSwhKz5fI/AAAAAAAAAFs/IvXW6ca5RGE/S220/profile.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-RLEhUA4o6zA/TzbwmBf_9OI/AAAAAAAAASU/VGrkC1YkEnE/s72-c/page2.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7964484936470829118.post-6187226571381834210</id><published>2012-02-10T08:00:00.000+09:00</published><updated>2012-02-11T07:17:32.370+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tips'/><category scheme='http://www.blogger.com/atom/ns#' term='scalaz'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>Scala Tips / Option - Index</title><content type='html'>&lt;div&gt;&lt;p&gt;Optionが一段落したので記事の一覧表をまとめておきます。&lt;/p&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;項目&lt;/th&gt;&lt;th&gt;内容&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;a href="http://modegramming.blogspot.com/2012/01/scala-tipsoption.html"&gt;Option&lt;/a&gt;&lt;/td&gt;&lt;td&gt;値の取得&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href="http://modegramming.blogspot.com/2012/01/scala-tips-option-2.html"&gt;Option (2)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;nullをOptionに持ち上げる方法&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href="http://modegramming.blogspot.com/2012/01/scala-tips-option-3.html"&gt;Option (3)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;map&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href="http://modegramming.blogspot.com/2012/01/scala-tips-option-4.html"&gt;Option (4)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;withFilter&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href="http://modegramming.blogspot.com/2012/02/scala-tips-option-5.html"&gt;Option (5)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;collect&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href="http://modegramming.blogspot.com/2012/02/scala-tips-option-6.html"&gt;Option (6)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;flatMap&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href="http://modegramming.blogspot.com/2012/02/scala-tips-option-7.html"&gt;Option (7)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;for式&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href="http://modegramming.blogspot.com/2012/02/scala-tips-option-8.html"&gt;Option (8)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;getOrElse&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href="http://modegramming.blogspot.com/2012/02/scala-tips-option-9.html"&gt;Option (9)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;withFilter, map, getOrElse&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href="http://modegramming.blogspot.com/2012/02/scala-tips-option-10-exception.html"&gt;Option (10) - Exception&lt;/a&gt;&lt;/td&gt;&lt;td&gt;flatMap, Exceptionハンドリング&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href="http://modegramming.blogspot.com/2012/02/scala-tips-option-11-somenone.html"&gt;Option (11) - Some／None&lt;/a&gt;&lt;/td&gt;&lt;td&gt;SomeとNoneの記述方法&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href="http://modegramming.blogspot.com/2012/01/scala-tips-null.html"&gt;null&lt;/a&gt;&lt;/td&gt;&lt;td&gt;nullを値に持ち上げる方法&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;Optionをnullの問題を回避するためのコンテナとみるとちょっとした便利機能のように思ってしまいますが、成功/失敗の計算文脈を実現するモナドとしてみると、関数型プログラミングの広大な世界が垣間見えてきます。&lt;/p&gt;&lt;p&gt;Optionについては以下の記事も参考になると思います。&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://modegramming.blogspot.com/2010/02/option.html"&gt;Option&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://modegramming.blogspot.com/2010/03/optionnull.html"&gt;Optionとnull&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://modegramming.blogspot.com/2010/03/optionlistforflatmap.html"&gt;OptionとListとforとflatMap&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://modegramming.blogspot.com/2010/03/scalajava.html"&gt;Scalaのロジック、Javaのロジック&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7964484936470829118-6187226571381834210?l=modegramming.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://modegramming.blogspot.com/feeds/6187226571381834210/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://modegramming.blogspot.com/2012/02/scala-tips-option-index.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/6187226571381834210'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/6187226571381834210'/><link rel='alternate' type='text/html' href='http://modegramming.blogspot.com/2012/02/scala-tips-option-index.html' title='Scala Tips / Option - Index'/><author><name>asami</name><uri>http://www.blogger.com/profile/12083671403528595185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_4HtJQwbXqEY/S4sSwhKz5fI/AAAAAAAAAFs/IvXW6ca5RGE/S220/profile.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7964484936470829118.post-1450392056256592136</id><published>2012-02-09T08:00:00.000+09:00</published><updated>2012-02-12T05:58:11.587+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tips'/><category scheme='http://www.blogger.com/atom/ns#' term='scalaz'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>Scala Tips / Option (11) - Some/None</title><content type='html'>&lt;div&gt;&lt;p&gt;OptionのサブクラスであるSomeとNoneを生成するイディオムです。&lt;/p&gt;&lt;div&gt;&lt;h4&gt;Scala&lt;/h4&gt;&lt;p&gt;Some[Int]とNoneは以下のようにして生成します。(Noneは実際にはシングルトンです。)&lt;/p&gt;&lt;pre name="code" class="java"&gt;val a = Some(10)&lt;br /&gt;val a = None&lt;/pre&gt;&lt;p&gt;通常はこの生成方法で良いのですが、一つ問題があります。Some(10)の型はOption[Int]ではなくSome[Int]に、Noneの型もOption[Int]ではなくNone[Nothing]になってしまいます。&lt;/p&gt;&lt;pre class="console"&gt;scala&amp;gt; val a = Some(10)&lt;br /&gt;a: Some[Int] = Some(10)&lt;br /&gt;&lt;br /&gt;scala&amp;gt; val a = None&lt;br /&gt;a: None.type = None&lt;/pre&gt;&lt;p&gt;このため、型をOption[Int]にするためには以下のように変数定義に記述するか:&lt;/p&gt;&lt;pre name="code" class="java"&gt;val a: Option[Int] = Some(10)&lt;br /&gt;val a: Option[Int] = None&lt;/pre&gt;&lt;p&gt;オブジェクト側に型注釈を付ける必要があります。&lt;/p&gt;&lt;pre name="code" class="java"&gt;val a = Some(10): Option[Int]&lt;br /&gt;val a = None: Option[Int]&lt;/pre&gt;&lt;p&gt;いずれもちょっと冗長ですね。&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;Scalaz&lt;/h4&gt;&lt;p&gt;Scalazでは、以下の記述方法でSomeとNoneを生成することが可能です。&lt;/p&gt;&lt;pre name="code" class="java"&gt;val a = 10.some&lt;br /&gt;val a = none[Int]&lt;/pre&gt;&lt;p&gt;「10.some」のように任意のオブジェクトのsomeメソッド(Scalazが追加)によってOption[Int]型のインスタンスとしてSome[Int]を生成することができます。また、「none[Int]」のように型名を指定することでOption[Int]型のインスタンスとしてNoneを生成することができます。&lt;/p&gt;&lt;pre class="console"&gt;scala&amp;gt; 1.some&lt;br /&gt;res53: Option[Int] = Some(1)&lt;br /&gt;&lt;br /&gt;scala&amp;gt; none[Int]&lt;br /&gt;res54: Option[Int] = None&lt;/pre&gt;&lt;div&gt;&lt;h5&gt;BooleanをOptionに変換&lt;/h5&gt;&lt;p&gt;Scalazでは、Optionを生成する方法としてBooleanのoptinメソッドを使用する方法があります。(&lt;a href="http://modegramming.blogspot.com/2012/02/scala-tips-option-6.html"&gt;Option(6)&lt;/a&gt;)&lt;/p&gt;&lt;pre name="code" class="java"&gt;def f(cond: Boolean, value: Int): Option[Int] = {&lt;br /&gt;  cond.option(value)&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;条件が真だった場合は指定した値でSomeを、偽だった場合はNoneを作成します。BooleanをOptionに変換する機能ということができます。&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;ノート&lt;/h4&gt;&lt;p&gt;&lt;code&gt;Some(10)&lt;/code&gt; と &lt;code&gt;10.some&lt;/code&gt; の違いは、一つは見た目として関数型プログラミング的に &lt;code&gt;10.some&lt;/code&gt; の方が見やすいというのがあると思います。この問題はテーマとしていずれ取り上げたいと思います。これは、あくまで主観的なものなので、見た目の問題だけならどちらの記法を採るのかというのは好みの問題となります。&lt;/p&gt;&lt;p&gt;ということで、もっと実利的な意味で &lt;code&gt;10.some&lt;/code&gt; が有益なケースというのを知りたいところです。&lt;/p&gt;&lt;p&gt;Scalazの &lt;code&gt;10.some&lt;/code&gt; という記法が具体的に役に立つのは、関数の引数で型情報まで記述する場合です。&lt;/p&gt;&lt;p&gt;典型的な例がfoldLeftメソッドです。foldLeftメソッドはで畳込みの結果を積算する値の型は、引数に指定する値に付帯する形で指定しなければなりません。&lt;/p&gt;&lt;p&gt;List#foldLeftメソッドを使ってList[Int]の内容を積算するプログラムを例に考えます。Int値がすべて0以上の場合は積算を行いますが、一つでも0未満のものが合った場合はエラーとします。積算が成功した場合はSome[Int]を、失敗した場合はNoneを返します。&lt;/p&gt;&lt;p&gt;まず、初期値として普通にSome(0)を指定してみます。&lt;/p&gt;&lt;p&gt;以下の指定はコンパイルエラーになります。初期値として &lt;code&gt;Some(0)&lt;/code&gt; とするとSome[Int]型になってしまうので、Option[Int]として演算ができなくなってしまうわけです。&lt;/p&gt;&lt;pre name="code" class="java"&gt;def f(l: List[Int]): Option[Int] = {&lt;br /&gt;  l.foldLeft(Some(0)) { (a, e) =&amp;gt;&lt;br /&gt;    if (e &amp;gt;= 0) a.map(_ + e) else None&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;これは、以下のように型を明記すれば解決しますが、ちょっと冗長ですね。&lt;/p&gt;&lt;pre name="code" class="java"&gt;def f(l: List[Int]): Option[Int] = {&lt;br /&gt;  l.foldLeft(Some(0): Option[Int]) { (a, e) =&amp;gt;&lt;br /&gt;    if (e &amp;gt;= 0) a.map(_ + e) else None&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Scalazの &lt;code&gt;0.some&lt;/code&gt; は型がOption[Int]になるので、この問題が発生しません。&lt;/p&gt;&lt;pre name="code" class="java"&gt;def f(l: List[Int]): Option[Int] = {&lt;br /&gt;  l.foldLeft(0.some) { (a, e) =&amp;gt;&lt;br /&gt;    if (e &amp;gt;= 0) a.map(_ + e) else none&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div&gt;&lt;h5&gt;Optionに対するfoldLeftでの畳込み&lt;/h5&gt;&lt;p&gt;ついでなのでOption操作の復習も兼ねて、foldLeftでOptionに対する畳込みをいくつか書いてみました。&lt;/p&gt;&lt;pre name="code" class="java"&gt;def f1(l: List[Int]): Option[Int] = {&lt;br /&gt;  l.foldLeft(0.some) { (a, e) =&amp;gt;&lt;br /&gt;    if (e &amp;gt;= 0) a.map(_ + e) else none&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;def f2(l: List[Int]): Option[Int] = {&lt;br /&gt;  l.foldLeft(0.some) { (a, e) =&amp;gt;&lt;br /&gt;    (e &amp;gt;= 0).fold(a.map(_ + e), none)&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;def f3(l: List[Int]): Option[Int] = {&lt;br /&gt;  l.foldLeft(0.some) { (a, e) =&amp;gt;&lt;br /&gt;    for (x &amp;lt;- a if e &amp;gt;= 0) yield x + e&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;def f4(l: List[Int]): Option[Int] = {&lt;br /&gt;  l.foldLeft(0.some) { (a, e) =&amp;gt;&lt;br /&gt;    a.withFilter(_ =&amp;gt; e &amp;gt;= 0).map(_ + e)&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;同じ処理でも色々な書き方ができます。もう少し複雑な処理だと、それぞれの書き方との相性が出てくるので、色々ストックしておいて適材適所で選んでいくようにしたいですね。&lt;/p&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;関数&lt;/th&gt;&lt;th&gt;説明&lt;/th&gt;&lt;th&gt;参考&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;f1&lt;/td&gt;&lt;td&gt;if式を使った普通の手法&lt;/td&gt;&lt;td&gt;&lt;a href="http://modegramming.blogspot.com/2012/01/scala-tips-option-4.html"&gt; Option(4)&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;f2&lt;/td&gt;&lt;td&gt;Booleanのfoldを使った手法&lt;/td&gt;&lt;td&gt;&lt;a href="http://modegramming.blogspot.com/2012/02/scala-tips-option-8.html"&gt;Option(8)&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;f3&lt;/td&gt;&lt;td&gt;for式を使った手法&lt;/td&gt;&lt;td&gt;&lt;a href="http://modegramming.blogspot.com/2012/02/scala-tips-option-7.html"&gt;Option(7)&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;f4&lt;/td&gt;&lt;td&gt;withFilterとmapを使った手法&lt;/td&gt;&lt;td&gt;&lt;a href="http://modegramming.blogspot.com/2012/01/scala-tips-option-4.html"&gt;Option(4)&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;追記 (2012-02-12)&lt;/h4&gt;&lt;div&gt;&lt;p&gt;xuwei_kさんのご指摘で抜けがあることが分かったので補足です。&lt;/p&gt;&lt;p&gt;&lt;code&gt;Some(10)&lt;/code&gt; と &lt;code&gt;10.some&lt;/code&gt; の比較をして、後者の方がOption[Int]という型になるので、使いやすいという話をしました。この点について補足です。&lt;/p&gt;&lt;p&gt;Scalaの標準ライブラリでは &lt;code&gt;Some(10)&lt;/code&gt; とは別に &lt;code&gt;Option(10)&lt;/code&gt; というOptionの生成方法を用意していて、この場合はOption[Int]型の &lt;code&gt;Some(10)&lt;/code&gt; を生成します。本記事の用途では、Someに関しては &lt;code&gt;Option(10)&lt;/code&gt; の方法でも実現可能です。Scalazを使わない場合は、こちらを使うとよいでしょう。&lt;/p&gt;&lt;p&gt;ただし、Noneに関しては、ちょっとややこしくなります。&lt;/p&gt;&lt;p&gt;&lt;code&gt;Option(null)&lt;/code&gt; で生成できるものの型がOption[NULL]になってしまいます。&lt;/p&gt;&lt;p&gt;格納するオブジェクトがAnyRefである場合には、&lt;code&gt;Option[String](null)&lt;/code&gt;や&lt;code&gt;Option(null: String)&lt;/code&gt; という記法が可能です。(関連「&lt;a href="http://modegramming.blogspot.com/2012/01/scala-tips-null.html"&gt;null&lt;/a&gt;」)&lt;/p&gt;&lt;pre class="console"&gt;scala&amp;gt; Option[String](null)&lt;br /&gt;res32: Option[String] = None&lt;br /&gt;&lt;br /&gt;scala&amp;gt; Option(null: String)&lt;br /&gt;res29: Option[String] = None&lt;/pre&gt;&lt;p&gt;ただし、Anyの場合は使えません。&lt;/p&gt;&lt;pre class="console"&gt;scala&amp;gt; Option[Int](null)&lt;br /&gt;&amp;lt;console&amp;gt;:8: error: type mismatch;&lt;br /&gt; found   : Null(null)&lt;br /&gt; required: Int&lt;br /&gt;Note that implicit conversions are not applicable because they are ambiguous:&lt;br /&gt; both method Integer2intNullConflict in class LowPriorityImplicits of type (x: Null)Int&lt;br /&gt; and method Integer2int in object Predef of type (x: java.lang.Integer)Int&lt;br /&gt; are possible conversion functions from Null(null) to Int&lt;br /&gt;              Option[Int](null)&lt;br /&gt;                          ^&lt;br /&gt;&lt;br /&gt;scala&amp;gt; Option(null: Int)&lt;br /&gt;&amp;lt;console&amp;gt;:8: error: type mismatch;&lt;br /&gt; found   : Null(null)&lt;br /&gt; required: Int&lt;br /&gt;Note that implicit conversions are not applicable because they are ambiguous:&lt;br /&gt; both method Integer2intNullConflict in class LowPriorityImplicits of type (x: Null)Int&lt;br /&gt; and method Integer2int in object Predef of type (x: java.lang.Integer)Int&lt;br /&gt; are possible conversion functions from Null(null) to Int&lt;br /&gt;              Option(null: Int)&lt;br /&gt;                     ^&lt;/pre&gt;&lt;p&gt;以上のようにNoneの場合は、色々と考えないといけないことがあります。この辺の事情を覚えておいてプログラミング中に使い分けても、特にメリットがあるところではないので、Noneを生成する場合は変数や関数シグネチャの型定義またはオブジェクトに対する型注釈で型を補うという方針にしておくのがよいと思います。&lt;/p&gt;&lt;pre class="console"&gt;scala&amp;gt; None: Option[Int]&lt;br /&gt;res31: Option[Int] = None&lt;/pre&gt;&lt;p&gt;Scalazを使っている場合は、本文中にあったように、&lt;code&gt;10.some&lt;/code&gt; , &lt;code&gt;none[Int]&lt;/code&gt; の記法を使うようにするのが分かりやすくてよいでしょう。&lt;/p&gt;&lt;/div&gt;&lt;h4&gt;諸元&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Scala 2.9.1&lt;/li&gt;&lt;li&gt;Scalaz 6.0.3&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7964484936470829118-1450392056256592136?l=modegramming.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://modegramming.blogspot.com/feeds/1450392056256592136/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://modegramming.blogspot.com/2012/02/scala-tips-option-11-somenone.html#comment-form' title='3 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/1450392056256592136'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/1450392056256592136'/><link rel='alternate' type='text/html' href='http://modegramming.blogspot.com/2012/02/scala-tips-option-11-somenone.html' title='Scala Tips / Option (11) - Some/None'/><author><name>asami</name><uri>http://www.blogger.com/profile/12083671403528595185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_4HtJQwbXqEY/S4sSwhKz5fI/AAAAAAAAAFs/IvXW6ca5RGE/S220/profile.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7964484936470829118.post-931517959057754164</id><published>2012-02-08T08:00:00.000+09:00</published><updated>2012-02-08T08:00:02.269+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tips'/><category scheme='http://www.blogger.com/atom/ns#' term='scalaz'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>Scala Tips / Option (10) - Exception</title><content type='html'>&lt;div&gt;&lt;p&gt;Optionから値を取り出すイディオムです。&lt;/p&gt;&lt;p&gt;Optionから値を取り出す際に、以下の表の演算を行う方法についてみてきました。&lt;/p&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;条件&lt;/th&gt;&lt;th&gt;結果&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Option[A]に有効な値が入っている&lt;/td&gt;&lt;td&gt;Some[B]&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Option[A]に無効な値が入っている&lt;/td&gt;&lt;td&gt;None&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Option[A]がNone&lt;/td&gt;&lt;td&gt;None&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;今回は「Option[A]に無効な値が入っている」の判定で例外を使用するケースです。例外を使うと、プログラミングにも少なからぬ影響が出てきます。&lt;/p&gt;&lt;p&gt;以下では、Option[String]からOption[Int]への変換を例に考えてみます。Optionに入っているStringがIntに変換できる場合は有効となり、Some[Int]が処理結果となります。一方、変換できない場合は無効となりNoneが処理結果となります。&lt;/p&gt;&lt;p&gt;ここで、StringからIntへの変換ができない事の判定に例外を使用します。&lt;/p&gt;&lt;p&gt;(&lt;a href="http://modegramming.blogspot.com/2012/01/scala-tipsoption.html"&gt;分類の基準&lt;/a&gt;)&lt;/p&gt;&lt;div&gt;&lt;h4&gt;Java風&lt;/h4&gt;&lt;p&gt;if式でOption#isDefinedを使って値の有無を判定します。&lt;/p&gt;&lt;p&gt;文字列が整数値に合致しなかった場合String#toIntメソッドがNumberFormatExceptionをスローするので、これをtry/catch文でキャッチしています。&lt;/p&gt;&lt;p&gt;引数がNoneの場合とNumberFormatExceptionをキャッチした時がNone、toIntで整数値が得られた場合はSome[Int]が演算結果となります。&lt;/p&gt;&lt;pre name="code" class="java"&gt;def f(a: Option[String]): Option[Int] = {&lt;br /&gt;  if (a.isDefined) {&lt;br /&gt;    try {&lt;br /&gt;      Some(a.get.toInt)&lt;br /&gt;    } catch {&lt;br /&gt;      case e: NumberFormatException =&amp;gt; None&lt;br /&gt;    }&lt;br /&gt;  } else None&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;Scala風&lt;/h4&gt;&lt;p&gt;match式を使うと以下のようになります。try/catch文が入るとプログラムの見通しはJava風とそれほど変わらなくなりますね。&lt;/p&gt;&lt;pre name="code" class="java"&gt;def f(a: Option[String]): Option[Int] = {&lt;br /&gt;  a match {&lt;br /&gt;    case Some(b) =&amp;gt; {&lt;br /&gt;      try {&lt;br /&gt;        Some(a.get.toInt)&lt;br /&gt;      } catch {&lt;br /&gt;        case e: NumberFormatException =&amp;gt; None&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;    case None =&amp;gt; None&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p/&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;Scala&lt;/h4&gt;&lt;p&gt;Optionの処理にmapメソッドを使うのがScala的なコーディングです。ただし、今回のケースでは例外をキャッチする処理を行う必要があります。&lt;/p&gt;&lt;pre name="code" class="java"&gt;def f(a: Option[String]): Option[Int] = {&lt;br /&gt;  try {&lt;br /&gt;    a.map(_.toInt)&lt;br /&gt;  } catch {&lt;br /&gt;    case e: NumberFormatException =&amp;gt; None&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;mapメソッドの外側でtry/catchを使って例外をキャッチするのは、ちょっと美しくありません。例外に依存するロジックは部品化の妨げになるので、できるだけ局所化して隠蔽したいところです。&lt;/p&gt;&lt;p&gt;このためには、mapメソッドの中で例外をキャッチしたいわけですが、この場合は例外をキャッチしたときに、成功の文脈から失敗の文脈への切り替えを行う必要があるので、&lt;a href="http://modegramming.blogspot.com/2012/02/scala-tips-option-6.html"&gt;Option(6)&lt;/a&gt;で取り上げたOption#flatMapメソッドを使用します。&lt;/p&gt;&lt;pre name="code" class="java"&gt;def f(a: Option[String]): Option[Int] = {&lt;br /&gt;  a.flatMap { b =&amp;gt;&lt;br /&gt;    try {&lt;br /&gt;      Some(b.toInt)&lt;br /&gt;    } catch {&lt;br /&gt;      case e: NumberFormatException =&amp;gt; None&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;例外をキャッチしてOptionに変換するのはScalaでは頻出の処理なので、専用の関数がオブジェクトscala.util.control.Exceptionに用意されています。よく使うのがcatching関数とallCatch関数です。&lt;/p&gt;&lt;p&gt;catching関数は、キャッチする例外を列挙して指定することができます。catching関数から返されるCatchオブジェクトのoptメソッドで例外の発生の有無をOptionに変換することができます。&lt;/p&gt;&lt;pre name="code" class="java"&gt;import scala.util.control.Exception._    &lt;br /&gt;&lt;br /&gt;def f(a: Option[String]): Option[Int] = {&lt;br /&gt;  a.flatMap { b =&amp;gt;&lt;br /&gt;    catching(classOf[NumberFormatException]).opt(b.toInt)&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;多くの場合はNumberFormatException以外の例外が発生しても関数のエラーとして返して大丈夫だと思われるので、すべての例外をキャッチするallCatching関数を使う方法も有力です。&lt;/p&gt;&lt;pre name="code" class="java"&gt;import scala.util.control.Exception._    &lt;br /&gt;&lt;br /&gt;def f(a: Option[String]): Option[Int] = {&lt;br /&gt;  a.flatMap { b =&amp;gt;&lt;br /&gt;    allCatch.opt(b.toInt)&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;Scalaz&lt;/h4&gt;&lt;p&gt;Scalaz流のエレガントな書き方はないと思います。&lt;/p&gt;&lt;p&gt;汎用的な方法ではありませんが、今回の例題である文字列を数値に変換する処理に関しては、ScalazのparseIntメソッド(parseFloatその他もあります)が利用できます。&lt;/p&gt;&lt;pre name="code" class="java"&gt;def f(a: Option[String]): Option[Int] = {&lt;br /&gt;  a.flatMap(_.parseInt.toOption)&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;parseIntメソッドは数値への変換の成否をValidationオブジェクトとして通知します。ValidationのtoOptionメソッドでOptionに変換します。&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;ノート&lt;/h4&gt;&lt;p&gt;例外を関数型プログラミングの中でどう扱っていくのかというのは、ちょっと悩むところですが、Java由来のOOPとのハイブリッドであるScalaでは避けて通ることはできません。&lt;/p&gt;&lt;p&gt;例外処理の考え方はいずれイディオムとしてまとめる予定ですが、今の所、できるだけ早い段階でOption, Either, Validationにして関数合成を軸としたMonadic演算のラインに乗せる方向が、よいのではないかと考えています。&lt;/p&gt;&lt;p&gt;そういう意味で、Scala 2.8から入ってきたscala.util.control.Exceptionは重要な機能ということができます。&lt;/p&gt;&lt;p&gt;現段階では、Optionまでしか取り上げていないので、Either, Validationが終わったたところで改めて考えることにします。&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;諸元&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Scala 2.9.1&lt;/li&gt;&lt;li&gt;Scalaz 6.0.3&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7964484936470829118-931517959057754164?l=modegramming.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://modegramming.blogspot.com/feeds/931517959057754164/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://modegramming.blogspot.com/2012/02/scala-tips-option-10-exception.html#comment-form' title='1 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/931517959057754164'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/931517959057754164'/><link rel='alternate' type='text/html' href='http://modegramming.blogspot.com/2012/02/scala-tips-option-10-exception.html' title='Scala Tips / Option (10) - Exception'/><author><name>asami</name><uri>http://www.blogger.com/profile/12083671403528595185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_4HtJQwbXqEY/S4sSwhKz5fI/AAAAAAAAAFs/IvXW6ca5RGE/S220/profile.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7964484936470829118.post-6558030448504646500</id><published>2012-02-07T08:00:00.001+09:00</published><updated>2012-02-07T08:00:04.245+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tips'/><category scheme='http://www.blogger.com/atom/ns#' term='scalaz'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>Scala Tips / Option (9)</title><content type='html'>&lt;div&gt;&lt;p&gt;Optionから値を取り出すイディオムです。&lt;/p&gt;&lt;p&gt;Optionから値を取り出す処理として以下の2つのコーディングパターンを挙げました。&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Option[A]からOption[B]に変換&lt;/li&gt;&lt;li&gt;Option[A]からBに変換&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;前回は、後者のOption[A]からBへの変換について、基本的なイディオムを紹介しました。&lt;/p&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;条件&lt;/th&gt;&lt;th&gt;結果&lt;/th&gt;&lt;th&gt;演算&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Option[A]がSome[A]&lt;/td&gt;&lt;td&gt;B&lt;/td&gt;&lt;td&gt;AからBを計算&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Option[A]がNone&lt;/td&gt;&lt;td&gt;B&lt;/td&gt;&lt;td&gt;デフォルト値&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;今回は、Option[A]がNoneの場合だけでなく、Some[A]の値が条件を満たさない場合も、デフォルト値を返すようにします。&lt;/p&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;条件&lt;/th&gt;&lt;th&gt;結果&lt;/th&gt;&lt;th&gt;演算&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Option[A]に有効な値が入っている&lt;/td&gt;&lt;td&gt;B&lt;/td&gt;&lt;td&gt;AからBを計算&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Option[A]に無効な値が入っている&lt;/td&gt;&lt;td&gt;B&lt;/td&gt;&lt;td&gt;デフォルト値&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Option[A]がNone&lt;/td&gt;&lt;td&gt;B&lt;/td&gt;&lt;td&gt;デフォルト値&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;以下では、Option[Int]からStringへの変換を例に考えてみます。ただし、Intは0以上のものが有効という条件を追加します。Optionに入っているIntが0以上の場合、Stringが処理結果となります。一方、0未満の場合は無効となり空文字列「&amp;quot;&amp;quot;」が処理結果となります。またOption[A]がNoneの場合も空文字列「&amp;quot;&amp;quot;」が処理結果となります。&lt;/p&gt;&lt;div&gt;&lt;h4&gt;Java風&lt;/h4&gt;&lt;p&gt;if式でOption#isDefinedを使って値の有無を判定します。isDefinedAtメソッドが一回、getメソッドが二回が泣き別れになってしまいます。&lt;/p&gt;&lt;pre name="code" class="java"&gt;def f(a: Option[Int]): String = {&lt;br /&gt;  if (a.isDefined &amp;amp;&amp;amp; a.get &amp;gt;= 0) a.get.toString&lt;br /&gt;  else &amp;quot;&amp;quot;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;Scala風&lt;/h4&gt;&lt;p&gt;match式を使うと以下のようになります。こちらの方が綺麗ですね。&lt;/p&gt;&lt;pre name="code" class="java"&gt;def f(a: Option[Int]): String = {&lt;br /&gt;  a match {&lt;br /&gt;    case Some(b) if (b &amp;gt;= 0) =&amp;gt; b.toString&lt;br /&gt;    case _ =&amp;gt; &amp;quot;&amp;quot;&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;Scala&lt;/h4&gt;&lt;p&gt;&lt;a href="http://modegramming.blogspot.com/2012/01/scala-tips-option-4.html"&gt;Option(4)&lt;/a&gt;のwithFilterメソッド、mapメソッドと&lt;a href="http://modegramming.blogspot.com/2012/01/scala-tipsoption.html"&gt;Option&lt;/a&gt; のgetOrElseメソッドの合わせ技で実現できます。&lt;/p&gt;&lt;pre name="code" class="java"&gt;def f(a: Option[Int]): String = {&lt;br /&gt;  a.withFilter(_ &amp;gt;= 0).map(b.toString) getOrElse &amp;quot;&amp;quot;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;Scalaz&lt;/h4&gt;&lt;p&gt;Scalazの場合はOption(7)の技法に&lt;a href="http://modegramming.blogspot.com/2012/01/scala-tips-option-4.html"&gt;Option(4)&lt;/a&gt;のwithFilterメソッドまたはfilterメソッドを組合わせて、実現できます。&lt;/p&gt;&lt;p&gt;注意点としては、cataメソッドとfoldメソッドの場合はwithFilterではなくてfilterを使う必要があります。cataメソッドとfoldメソッドはScalazが拡張したメソッドで、ScalaのWithFilterオブジェクトは扱えないからです。&lt;/p&gt;&lt;pre name="code" class="java"&gt;def f(a: Option[Int]): String = {&lt;br /&gt;  a.withFilter(_ &amp;gt;= 0).map(_.toString) | &amp;quot;&amp;quot;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;pre name="code" class="java"&gt;def f(a: Option[Int]): String = {&lt;br /&gt;  a.filter(_ &amp;gt;= 0).cata(_.toString, &amp;quot;&amp;quot;)&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;pre name="code" class="java"&gt;def f(a: Option[Int]): String = {&lt;br /&gt;  a.filter(_ &amp;gt;= 0).fold(_.toString, &amp;quot;&amp;quot;)&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;&lt;/p&gt;&lt;pre name="code" class="java"&gt;def f(a: Option[Int]): String = {&lt;br /&gt;  a.withFilter(_ &amp;gt;= 0).map(_.toString) orZero&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;pre name="code" class="java"&gt;def f(a: Option[Int]): String = {&lt;br /&gt;  ~a.withFilter(_ &amp;gt;= 0).map(_.toString)&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;ノート&lt;/h4&gt;&lt;p&gt;今回は&lt;a href="http://modegramming.blogspot.com/2012/01/scala-tips-option-4.html"&gt;Option(4)&lt;/a&gt;のwithFilterメソッドを組み合わせてみましたが、&lt;a href="http://modegramming.blogspot.com/2012/01/scala-tips-option-5.html"&gt;Option(5)&lt;/a&gt;のcollectメソッド、&lt;a href="http://modegramming.blogspot.com/2012/01/scala-tips-option-6.html"&gt;Option(6)&lt;/a&gt;のflatMapメソッドでも同じように実現できます。&lt;/p&gt;&lt;p&gt;要するに、Option上で(つまり成功失敗の計算文脈上で)計算を続け、最後にcataメソッドなどでOptionから値を取り出すというメカニズムです。&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;諸元&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Scala 2.9.1&lt;/li&gt;&lt;li&gt;Scalaz 6.0.3&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7964484936470829118-6558030448504646500?l=modegramming.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://modegramming.blogspot.com/feeds/6558030448504646500/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://modegramming.blogspot.com/2012/02/scala-tips-option-9.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/6558030448504646500'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/6558030448504646500'/><link rel='alternate' type='text/html' href='http://modegramming.blogspot.com/2012/02/scala-tips-option-9.html' title='Scala Tips / Option (9)'/><author><name>asami</name><uri>http://www.blogger.com/profile/12083671403528595185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_4HtJQwbXqEY/S4sSwhKz5fI/AAAAAAAAAFs/IvXW6ca5RGE/S220/profile.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7964484936470829118.post-7364813931527280274</id><published>2012-02-06T08:00:00.001+09:00</published><updated>2012-02-06T08:42:52.598+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tips'/><category scheme='http://www.blogger.com/atom/ns#' term='scalaz'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>Scala Tips / Option (8)</title><content type='html'>&lt;div&gt;&lt;p&gt;Optionから値を取り出すイディオムです。&lt;/p&gt;&lt;p&gt;Optionから値を取り出す処理として以下の2つのコーディングパターンを挙げました。&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Option[A]からOption[B]に変換&lt;/li&gt;&lt;li&gt;Option[A]からBに変換&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;ここまではOption[A]からOption[B]への変換についてみてきました。今回はOption[A]からBへの変換について考えます。&lt;/p&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;条件&lt;/th&gt;&lt;th&gt;結果&lt;/th&gt;&lt;th&gt;演算&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Option[A]がSome[A]&lt;/td&gt;&lt;td&gt;B&lt;/td&gt;&lt;td&gt;AからBを計算&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Option[A]がNone&lt;/td&gt;&lt;td&gt;B&lt;/td&gt;&lt;td&gt;デフォルト値&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;Option[A]に有効な値が入っている場合は、この値からBを計算しますが、それ以外の場合はあらかじめ用意しているデフォルト値を返します。&lt;/p&gt;&lt;p&gt;以下では、Option[Int]からStringへの変換を例に考えてみます。Option[A]がNoneの場合はデフォルト値として空文字列「&amp;quot;&amp;quot;」を返すことにします。&lt;/p&gt;&lt;div&gt;&lt;h4&gt;Java風&lt;/h4&gt;&lt;p&gt;if式でOption#isDefinedを使って値の有無を判定します。デフォルト値の「&amp;quot;&amp;quot;」はelse句で指定します。&lt;/p&gt;&lt;pre name="code" class="java"&gt;def f(a: Option[Int]): String = {&lt;br /&gt;  if (a.isDefined) a.get.toString&lt;br /&gt;  else &amp;quot;&amp;quot;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;Scala風&lt;/h4&gt;&lt;p&gt;match式を使うと以下のようになります。こちらの方が綺麗ですね。&lt;/p&gt;&lt;pre name="code" class="java"&gt;def f(a: Option[Int]): String = {&lt;br /&gt;  a match {&lt;br /&gt;    case Some(b) =&amp;gt; b.toString&lt;br /&gt;    case None =&amp;gt; &amp;quot;&amp;quot;&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;Scala&lt;/h4&gt;&lt;p&gt;&lt;a href="http://modegramming.blogspot.com/2012/01/scala-tips-option-3.html"&gt;Option(3)&lt;/a&gt;のmapメソッドと&lt;a href="http://modegramming.blogspot.com/2012/01/scala-tipsoption.html"&gt;Option&lt;/a&gt; のgetOrElseメソッドの合わせ技で実現できます。&lt;/p&gt;&lt;pre name="code" class="java"&gt;def f(a: Option[Int]): String = {&lt;br /&gt;  a.map(_.toString) getOrElse &amp;quot;&amp;quot;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;Scalaz&lt;/h4&gt;&lt;p&gt;Scalazも、&lt;a href="http://modegramming.blogspot.com/2012/01/scala-tips-option-3.html"&gt;Option(3)&lt;/a&gt;のmapメソッドと&lt;a href="http://modegramming.blogspot.com/2012/01/scala-tipsoption.html"&gt;Option&lt;/a&gt; の「|」メソッドの合わせ技で実現できます。&lt;/p&gt;&lt;pre name="code" class="java"&gt;def f(a: Option[Int]): String = {&lt;br /&gt;  a.map(_.toString) | &amp;quot;&amp;quot;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Scalazでは、今回の用途にぴったりのメソッドOption#cataとOption#foldが用意されています。以下のように使用します。&lt;/p&gt;&lt;pre name="code" class="java"&gt;def f(a: Option[Int]): String = {&lt;br /&gt;  a.cata(_.toString, &amp;quot;&amp;quot;)&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;pre name="code" class="java"&gt;def f(a: Option[Int]): String = {&lt;br /&gt;  a.fold(_.toString, &amp;quot;&amp;quot;)&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;foldメソッドはcataメソッド(cataはcatamorphismの略)に分かりやすい名前をつけたもので、全く同じ動作をします。好きな方を使用すればよいでしょう。&lt;/p&gt;&lt;p&gt;以上が汎用的な方法ですが、条件が合えば以下のようにorZeroメソッドや「~」メソッドを使う方法も適用できます。&lt;/p&gt;&lt;pre name="code" class="java"&gt;def f(a: Option[Int]): String = {&lt;br /&gt;  a.map(_.toString) orZero&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;pre name="code" class="java"&gt;def f(a: Option[Int]): String = {&lt;br /&gt;  ~a.map(_.toString)&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;StringやIntといった型では、Scalazが初期値を持っています。この初期値を単位元と呼びます。デフォルト値がScalazが持っている初期値、すなわち単位元でよい場合は、これを利用するとデフォルト値の指定を省略することができます。今回使用している問題は、デフォルト値が「&amp;quot;&amp;quot;」ですが、これはStringの単位元と同じなので、この条件に当てはまります。&lt;/p&gt;&lt;p&gt;このため、OptionがNoneだった場合にデフォルト値として単位元を使うorZeroメソッドと単項演算子の「~」メソッドを使用することができるわけです。&lt;/p&gt;&lt;p&gt;orZeroメソッドと「~」メソッドは好みの方を使えばよいでしょう。orZeroメソッドを使うとちょっとごっつい感じですが、「~」メソッドは簡潔に記述できます。ただ、「~」は単項演算子で、見落としてしまいがちなのと、普通の単項演算子とはちょっと違う感触の使い方なので、プログラムの可読性が必ずしも高くないかもしれません。&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;ノート&lt;/h4&gt;&lt;p&gt;Scalazはモノイドという性質を扱うための型クラスMonoidを用意しています。モノイドの数学的な定義は&lt;a href="http://ja.wikipedia.org/wiki/%E3%83%A2%E3%83%8E%E3%82%A4%E3%83%89"&gt;こちら(Wikipedia)&lt;/a&gt;をご覧ください。&lt;/p&gt;&lt;p&gt;数学のモノイドはとても難しそうですが、Scalazの型クラスMonoidが適用されるオブジェクトはざっくりと以下の性質を持つと理解しておけばよいでしょう。&lt;/p&gt;&lt;ul&gt;&lt;li&gt;結合的な二項演算を持っている。多くの場合は加算。&lt;/li&gt;&lt;li&gt;&lt;a href="http://ja.wikipedia.org/wiki/%E5%8D%98%E4%BD%8D%E5%85%83"&gt;単位元(identity element)&lt;/a&gt; を持っている。&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;単位元はざっくりいうと &lt;code&gt;a+e&lt;/code&gt; や &lt;code&gt;e+a&lt;/code&gt; の二項演算を行った時に、 &lt;code&gt;a+e=a&lt;/code&gt; 、 &lt;code&gt;e+a=a&lt;/code&gt; となるeの事です。具体的には、 &lt;code&gt;1+0=1&lt;/code&gt; 、 &lt;code&gt;0+1=1&lt;/code&gt; における0、 &lt;code&gt;&amp;quot;Hello&amp;quot;+&amp;quot;&amp;quot;=&amp;quot;Hello&amp;quot;&lt;/code&gt; 、&lt;code&gt;&amp;quot;&amp;quot;+&amp;quot;Hello&amp;quot;&lt;/code&gt; における「&amp;quot;&amp;quot;」です。つまりIntの単位元は0、Stringの単位元は「&amp;quot;&amp;quot;」となります。&lt;/p&gt;&lt;p&gt;前述のorZeroメソッドや「~」メソッドは、モノイドの性質である単位元を使用しています。関数fは演算結果がStringでデフォルト値が「&amp;quot;&amp;quot;」となる演算を定義しているわけですが、このデフォルト値「&amp;quot;&amp;quot;」が、たまたまStringの単位元と同じなので、モノイドの性質を利用しているorZeroメソッドや「~」メソッドを使うことができるわけです。&lt;/p&gt;&lt;p&gt;Scalazでの代表的なMonoidのオブジェクトは、Int、String、Listといったものです。加算的な演算を持っているオブジェクトはだいたいMonoidとして操作できるようになっています。&lt;/p&gt;&lt;p&gt;Int、String、Listといったオブジェクトの共通の性質としてMonoidを定義することで、Monoidを対象にしたロジックを組めば、Int、String、Listといったオブジェクト指向的には全く異なったオブジェクトに同じロジックを適用できるようになります。たとえば、ScalazのValidationはこのモノイドをうまく利用しています。&lt;/p&gt;&lt;p&gt;今回のイディオムでは、Monoidの性質のごく一部を使っているだけでしたが、MonoidはScalazプログラミングでは頻出の極めて重要な型クラスなので少し詳しく説明してみました。&lt;/p&gt;&lt;p&gt;最後に、Monoidの動作をREPLで試してみたものを以下に示します。&lt;/p&gt;&lt;p&gt;単位元はmzero関数で取得できます。&lt;/p&gt;&lt;pre class="console"&gt;scala&amp;gt; mzero[Int]&lt;br /&gt;res4: Int = 0&lt;br /&gt;&lt;br /&gt;scala&amp;gt; mzero[String]&lt;br /&gt;res5: String = &amp;quot;&amp;quot;&lt;br /&gt;&lt;br /&gt;scala&amp;gt; mzero[List[Int]]&lt;br /&gt;res7: List[Int] = List()&lt;/pre&gt;&lt;p&gt;Monoidの二項演算は|+|メソッドまたは⊹メソッドです。(後者はUnicodeの数学記号になっています。)&lt;/p&gt;&lt;pre class="console"&gt;scala&amp;gt; 1 |+| 1&lt;br /&gt;res8: Int = 2&lt;br /&gt;&lt;br /&gt;scala&amp;gt; 1 |+| mzero[Int]&lt;br /&gt;res9: Int = 1&lt;br /&gt;&lt;br /&gt;scala&amp;gt; mzero[Int] |+| 1&lt;br /&gt;res10: Int = 1&lt;br /&gt;&lt;br /&gt;scala&amp;gt; &amp;quot;Hello&amp;quot; |+| &amp;quot;World&amp;quot;&lt;br /&gt;res15: java.lang.String = HelloWorld&lt;br /&gt;&lt;br /&gt;scala&amp;gt; &amp;quot;Hello&amp;quot; |+| mzero[String]&lt;br /&gt;res16: java.lang.String = Hello&lt;br /&gt;&lt;br /&gt;scala&amp;gt; mzero[String] |+| &amp;quot;World&amp;quot;&lt;br /&gt;res17: String = World&lt;br /&gt;&lt;br /&gt;scala&amp;gt; List(1, 2, 3) |+| List(4, 5, 6)&lt;br /&gt;res11: List[Int] = List(1, 2, 3, 4, 5, 6)&lt;br /&gt;&lt;br /&gt;scala&amp;gt; List(1, 2, 3) |+| mzero[List[Int]]&lt;br /&gt;res13: List[Int] = List(1, 2, 3)&lt;br /&gt;&lt;br /&gt;scala&amp;gt; mzero[List[Int]] |+| List(1, 2, 3)&lt;br /&gt;res14: List[Int] = List(1, 2, 3)&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;諸元&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Scala 2.9.1&lt;/li&gt;&lt;li&gt;Scalaz 6.0.3&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;/div&gt;&lt;h4&gt;追加&lt;/h4&gt;&lt;p&gt;一部、次回の記事が混入していたので、2月6日8時45分頃に内容を更新しました。&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7964484936470829118-7364813931527280274?l=modegramming.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://modegramming.blogspot.com/feeds/7364813931527280274/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://modegramming.blogspot.com/2012/02/scala-tips-option-8.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/7364813931527280274'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/7364813931527280274'/><link rel='alternate' type='text/html' href='http://modegramming.blogspot.com/2012/02/scala-tips-option-8.html' title='Scala Tips / Option (8)'/><author><name>asami</name><uri>http://www.blogger.com/profile/12083671403528595185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_4HtJQwbXqEY/S4sSwhKz5fI/AAAAAAAAAFs/IvXW6ca5RGE/S220/profile.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7964484936470829118.post-4084163102412162672</id><published>2012-02-03T08:00:00.000+09:00</published><updated>2012-02-03T08:00:00.525+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tips'/><category scheme='http://www.blogger.com/atom/ns#' term='scalaz'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>Scala Tips / Option (7)</title><content type='html'>&lt;div&gt;&lt;p&gt;Optionから値を取り出すイディオムです。&lt;/p&gt;&lt;p&gt;ここまで以下の演算と:&lt;/p&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;条件&lt;/th&gt;&lt;th&gt;結果&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Option［A］がSome［A］&lt;/td&gt;&lt;td&gt;Some［B］&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Option［A］がNone&lt;/td&gt;&lt;td&gt;None&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;以下の演算についてみてきました。&lt;/p&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;条件&lt;/th&gt;&lt;th&gt;結果&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Option[A]に有効な値が入っている&lt;/td&gt;&lt;td&gt;Some[B]&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Option[A]に無効な値が入っている&lt;/td&gt;&lt;td&gt;None&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Option[A]がNone&lt;/td&gt;&lt;td&gt;None&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;前者は、成功の文脈と失敗の文脈の切り替えが発生しない演算、後者は、成功の文脈と失敗の文脈の切り替えが発生する演算です。&lt;/p&gt;&lt;p&gt;今回はこの2つの演算をfor式を使って書いてみます。&lt;/p&gt;&lt;div&gt;&lt;h4&gt;Some[A]→Some[B]&lt;/h4&gt;&lt;p&gt;&lt;a href="http://modegramming.blogspot.com/2012/01/scala-tips-option-3.html"&gt;Option(3)&lt;/a&gt;で取り上げた成功の文脈と失敗の文脈の切り替えが発生しない演算です。以下の表に示す演算になります。&lt;/p&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;条件&lt;/th&gt;&lt;th&gt;結果&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Option［A］がSome［A］&lt;/td&gt;&lt;td&gt;Some［B］&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Option［A］がNone&lt;/td&gt;&lt;td&gt;None&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;Option[Int]からOption[String]へ変換は以下のようになります。&lt;/p&gt;&lt;pre name="code" class="java"&gt;def f(a: Option[Int]): Option[String] = {&lt;br /&gt;  for (b &lt;- a) yield b.toString&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Option(3)で使用したmapメソッドと同様に、Option[A]がNoneだった場合の処理を書く必要がありません。&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;Some[A]→None&lt;/h4&gt;&lt;p&gt;次は&lt;a href="http://modegramming.blogspot.com/2012/01/scala-tips-option-4.html"&gt;Option(4)&lt;/a&gt;で取り上げた成功の文脈と失敗の文脈の切り替えが発生する演算です。以下の表に示す演算になります。&lt;/p&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;条件&lt;/th&gt;&lt;th&gt;結果&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Option[A]に有効な値が入っている&lt;/td&gt;&lt;td&gt;Some[B]&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Option[A]に無効な値が入っている&lt;/td&gt;&lt;td&gt;None&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Option[A]がNone&lt;/td&gt;&lt;td&gt;None&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;Intは0以上のものが有効という条件付きのOption[Int]からOption[String]へ変換は以下のようになります。&lt;/p&gt;&lt;pre name="code" class="java"&gt;def f(a: Option[Int]): Option[String] = {&lt;br /&gt;  for (b &lt;- a if b &gt;= 0) yield b.toString&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;for式内のif句で、Some[A]をNoneに切り替える条件を指定することができます。&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;ノート&lt;/h4&gt;&lt;p&gt;Javaのfor文は構造化プログラミングにおける繰り返しを記述するための文でしたが、Scalaのfor式はモナドによる演算の文法糖衣となっています。&lt;/p&gt;&lt;p&gt;たとえば、以下のプログラムは、一見普通のfor文に見えますが、実際は0オブジェクト(Int型)のuntilメソッドが返すRangeオブジェクトがモナドで、このRangeオブジェクトに対するモナドの演算を行っています。&lt;/p&gt;&lt;pre name="code" class="java"&gt;for (i &lt;- 0 until 10) {&lt;br /&gt;  println(i)&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;モナドに対する演算を伝統的なfor文に見せているのがScalaの芸の細かいところで、Java言語などから移行する場合の敷居を低くしています。普通にプログラミングしていても自然にMonadicプログラミングをしているということになるわけで、使い方に慣れたところで徐々にMonadicプログラミング的な作法を取り入れていけばよいようになっています。&lt;/p&gt;&lt;p&gt;for式には、上記の(yield句なしの)for式と本文中で用いているyield句ありのfor式の2種類があります。&lt;/p&gt;&lt;p&gt;yield句ありのfor式の場合は、内部的に今までOption操作で使ってきた、mapメソッド、flatMapメソッド、withFilterメソッドを使って処理を行っています。つまり、完全な文法糖衣ということです。(yield句なしのfor式ではforeachメソッドを使います。)&lt;/p&gt;&lt;p&gt;今回取り上げているOptionから値を取り出すといった小さな処理では、mapメソッドなどを直接使ってもfor式を使っても効果はそれほど変わりません。好みの方を使うとよいでしょう。&lt;/p&gt;&lt;p&gt;ただし、&lt;a href="http://modegramming.blogspot.com/2012/02/scala-tips-option-6.html"&gt;Option(6)&lt;/a&gt;のようにflatMapメソッドを使って細かい操作をしたい場合や、&lt;a href="http://modegramming.blogspot.com/2012/02/scala-tips-option-5.html"&gt;Option(5)&lt;/a&gt;のようにcollectメソッドのようなfor式がカバーしていないメソッドを使いたい場合は、for式は諦めることになります。&lt;/p&gt;&lt;p&gt;逆に本格的なMonadicプログラミングを行う場合、for式を使うと見通しがよくなるケースがあるので、こういう場合はfor式を積極的に使っていきたいところです。&lt;/p&gt;&lt;p&gt;このあたりの選択のポイントについてもテーマとして考えていきたいと思います。&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;諸元&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Scala 2.9.1&lt;/li&gt;&lt;li&gt;Scalaz 6.0.3&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7964484936470829118-4084163102412162672?l=modegramming.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://modegramming.blogspot.com/feeds/4084163102412162672/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://modegramming.blogspot.com/2012/02/scala-tips-option-7.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/4084163102412162672'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/4084163102412162672'/><link rel='alternate' type='text/html' href='http://modegramming.blogspot.com/2012/02/scala-tips-option-7.html' title='Scala Tips / Option (7)'/><author><name>asami</name><uri>http://www.blogger.com/profile/12083671403528595185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_4HtJQwbXqEY/S4sSwhKz5fI/AAAAAAAAAFs/IvXW6ca5RGE/S220/profile.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7964484936470829118.post-1165848868573606730</id><published>2012-02-02T08:00:00.000+09:00</published><updated>2012-02-02T08:00:05.427+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tips'/><category scheme='http://www.blogger.com/atom/ns#' term='scalaz'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>Scala Tips / Option (6)</title><content type='html'>&lt;div&gt;&lt;p&gt;Optionから値を取り出すイディオムです。&lt;/p&gt;&lt;p&gt;以下の表が示す演算について考えています。&lt;/p&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;条件&lt;/th&gt;&lt;th&gt;結果&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Option[A]に有効な値が入っている&lt;/td&gt;&lt;td&gt;Some[B]&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Option[A]に無効な値が入っている&lt;/td&gt;&lt;td&gt;None&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Option[A]がNone&lt;/td&gt;&lt;td&gt;None&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;withFilterバージョン、collectバージョンに続いて、flatMapバージョンです。&lt;/p&gt;&lt;p&gt;引き続きIntは0以上のものが有効という条件付きのOption[Int]からOption[String]へ変換を例に考えてみます。&lt;/p&gt;&lt;p&gt;(&lt;a href="http://modegramming.blogspot.com/2012/01/scala-tipsoption.html"&gt;分類の基準&lt;/a&gt;)&lt;/p&gt;&lt;div&gt;&lt;h4&gt;Java風&lt;/h4&gt;&lt;p&gt;&lt;a href="http://modegramming.blogspot.com/2012/01/scala-tips-option-4.html"&gt;Option(4)&lt;/a&gt;と同じです。&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;Scala風&lt;/h4&gt;&lt;p&gt;&lt;a href="http://modegramming.blogspot.com/2012/01/scala-tips-option-4.html"&gt;Option(4)&lt;/a&gt;と同じです。&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;Scala&lt;/h4&gt;&lt;p&gt;Option[Int]のflatMapメソッドは、Option[Int]の格納する値であるIntを引数に取り、この場合はOption[String]を返す関数を実行します。&lt;a href="http://modegramming.blogspot.com/2012/01/scala-tips-option-3.html"&gt;Option(3)&lt;/a&gt;で取り上げた、mapメソッドの場合はIntを引数に取りStringを返す関数を実行し、その結果をmapメソッド側でOptionに詰めなおしますが、flatMapの場合は、StringをOptionに詰め直す作業もアプリケーション側の関数で行います。&lt;/p&gt;&lt;pre name="code" class="java"&gt;def f(a: Option[Int]): Option[String] = {&lt;br /&gt;  a.flatMap { b =&gt;&lt;br /&gt;    if (b &gt;= 0) Some(b.toString)&lt;br /&gt;    else None&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;Scalaz&lt;/h4&gt;&lt;p&gt;Scalazの場合もflatMapメソッドを使いますが、flatMapの中のロジックをより簡潔に記述することができます。&lt;/p&gt;&lt;pre name="code" class="java"&gt;def f(a: Option[Int]): Option[String] = {&lt;br /&gt;  a.flatMap(b =&gt; (b &gt;= 0).option(b.toString))&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Scalazでは、Booleanにoptionメソッドを拡張しています。optionメソッドでは、Booleanが真の場合、指定した関数が実行され、その結果をSomeに詰めたものが返されます。一方、偽の場合はNoneが返されます。&lt;/p&gt;&lt;p&gt;&lt;code&gt;(b &gt;= 0).option(b.toString)&lt;/code&gt;は、bの値が0以上の場合にbをStringにしたものをSome[String]に詰めて返し、そうでない場合はNoneを返します。&lt;/p&gt;&lt;p&gt;Scalazでは、このように式を簡潔に記述できる便利なメソッドが多数追加されています。&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;ノート&lt;/h4&gt;&lt;p&gt;今回の用途では、Optionのfilter/withFilterメソッドやcollectメソッドで十分に要件を満たせるので、イディオムとしてはこの2つだけもよかったのですが、プリケーションの意志で成功の文脈を失敗の文脈に切り替えるということを、もっと直接的な形で行う手法をマスターしておかないと応用が効かないので、flatMapメソッドも取り上げました。&lt;/p&gt;&lt;p&gt;以下の表の演算において:&lt;/p&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;条件&lt;/th&gt;&lt;th&gt;結果&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Option[A]に有効な値が入っている&lt;/td&gt;&lt;td&gt;Some[B]&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Option[A]に無効な値が入っている&lt;/td&gt;&lt;td&gt;None&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Option[A]がNone&lt;/td&gt;&lt;td&gt;None&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;「Option[A]に無効な値が入っている」部分が、アプリケーションの意志で成功の文脈を失敗の文脈に切り替えるところになります。&lt;/p&gt;&lt;p&gt;filter/withFilterメソッドやcollectメソッドは自動的にこの切り替えを行ってくれるわけですが、それぞれのメソッドの機能ははっきり決まっていて、提供された機能以外の用途に使うのは得策ではありません。&lt;/p&gt;&lt;p&gt;そういった汎用目的で成功の文脈を失敗の文脈に切り替える処理を行うのがflatMapメソッドです。&lt;/p&gt;&lt;p&gt;&lt;a href="http://modegramming.blogspot.com/2012/01/scala-tips-option-3.html"&gt;mapメソッド&lt;/a&gt;を使うと、成功の文脈における演算を記述することができましたが、成功の文脈を失敗の文脈に切り替えることはできませんでした。flatMapメソッドは、この切り替えを記述するためのメソッドというわけです。&lt;/p&gt;&lt;p&gt;モナドは計算文脈をカプセル化して扱う技術と考えることができます。(モナドの一種であるOptionは成功/失敗の文脈をカプセル化していました。)この計算文脈の操作に色々な手法が存在するわけですが、その中軸となるのがflatMapメソッドです。&lt;/p&gt;&lt;p&gt;flatMapメソッドを使いこなせるようになるとScalaプログラミングの幅がぐんと広がります。&lt;/p&gt;&lt;div&gt;&lt;h5&gt;filter, collect, flatMapの使い分け&lt;/h5&gt;&lt;p&gt;前回はfilterメソッドとcollectメソッドの使い分けについて説明しましたが、これにflatMapが加わりました。&lt;/p&gt;&lt;p&gt;filterメソッドやcollectメソッドは、使い方の形が決まっているので、これにぴったりハマるケースはfilterメソッドやcollectメソッドを使えばよいでしょう。&lt;/p&gt;&lt;p&gt;あまりぴったりはまらないケース、判定ロジックと生成ロジックが入り乱れているような場合に、flatMapメソッドを使うことになります。&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;諸元&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Scala 2.9.1&lt;/li&gt;&lt;li&gt;Scalaz 6.0.3&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7964484936470829118-1165848868573606730?l=modegramming.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://modegramming.blogspot.com/feeds/1165848868573606730/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://modegramming.blogspot.com/2012/02/scala-tips-option-6.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/1165848868573606730'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/1165848868573606730'/><link rel='alternate' type='text/html' href='http://modegramming.blogspot.com/2012/02/scala-tips-option-6.html' title='Scala Tips / Option (6)'/><author><name>asami</name><uri>http://www.blogger.com/profile/12083671403528595185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_4HtJQwbXqEY/S4sSwhKz5fI/AAAAAAAAAFs/IvXW6ca5RGE/S220/profile.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7964484936470829118.post-5544458180265636706</id><published>2012-02-01T08:00:00.000+09:00</published><updated>2012-02-01T08:00:00.522+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tips'/><category scheme='http://www.blogger.com/atom/ns#' term='scalaz'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>Scala Tips / Option (5)</title><content type='html'>&lt;div&gt;&lt;p&gt;Optionから値を取り出すイディオムです。&lt;/p&gt;&lt;p&gt;以下の表が示す演算について考えています。&lt;/p&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;条件&lt;/th&gt;&lt;th&gt;結果&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Option[A]に有効な値が入っている&lt;/td&gt;&lt;td&gt;Some[B]&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Option[A]に無効な値が入っている&lt;/td&gt;&lt;td&gt;None&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Option[A]がNone&lt;/td&gt;&lt;td&gt;None&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;withFilterバージョンに続いて、collectバージョンです。&lt;/p&gt;&lt;p&gt;前回はwithFilterメソッドとmapメソッドを組合せてこの表の演算を実現しましたが、これを一発で行うメソッドがあります。これがcollectメソッドです。&lt;/p&gt;&lt;p&gt;引き続きIntは0以上のものが有効という条件付きのOption[Int]からOption[String]へ変換を例に考えてみます。&lt;/p&gt;&lt;p&gt;(&lt;a href="http://modegramming.blogspot.com/2012/01/scala-tipsoption.html"&gt;分類の基準&lt;/a&gt;)&lt;/p&gt;&lt;div&gt;&lt;h4&gt;Java風&lt;/h4&gt;&lt;p&gt;Option(4)と同じです。&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;Scala風&lt;/h4&gt;&lt;p&gt;Option(4)と同じです。&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;Scala&lt;/h4&gt;&lt;p&gt;Option#collectメソッドにケースシーケンスを用いて部分関数(PartialFunction)を指定します。&lt;/p&gt;&lt;p&gt;指定した部分関数は、「指定されたInt値が0以上の場合には値をStringに変換する」というものです。指定されたInt値が0以上でない場合には、この部分関数は適用されません。&lt;/p&gt;&lt;p&gt;以下のプログラムでは、Option[Int]がSome[Int]の場合、部分関数が適用可能か(つまりInt値が0以上か)を検査し、適用可能の場合に部分関数を評価することでInt値をStringに変換します。collectメソッドはさらにStringをSome[String]に詰めなおして返します。また、Option[Int]がNoneの場合、あるいはSome[Int]だけど部分関数が適用可能でなかった場合はNoneを返します。&lt;/p&gt;&lt;pre name="code" class="java"&gt;def f(a: Option[Int]): Option[String] = {&lt;br /&gt;  a collect {&lt;br /&gt;    case b if b &gt;= 0 =&gt; b.toString&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;Scalaz&lt;/h4&gt;&lt;p&gt;Scalaz流のエレガントな書き方はないと思います。&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;ノート&lt;/h4&gt;&lt;p&gt;以下の表が示す演算について考えています。&lt;/p&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;条件&lt;/th&gt;&lt;th&gt;結果&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Option[A]に有効な値が入っている&lt;/td&gt;&lt;td&gt;Some[B]&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Option[A]に無効な値が入っている&lt;/td&gt;&lt;td&gt;None&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Option[A]がNone&lt;/td&gt;&lt;td&gt;None&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;withFilterメソッドとmapメソッドを組合せて実現していた処理をcollectメソッド一発で実現できました。&lt;/p&gt;&lt;p&gt;collectメソッドは非常に強力ですが、その力の源となっているのがPartialFunctionという関数オブジェクトです。部分関数と呼ぶこともできます。collectメソッドはPartialFunctionを引数に取ります。&lt;/p&gt;&lt;p&gt;関数の引数に指定された型の一部の値のみを評価できる関数が部分関数です。評価できない値に対しては関数は未定義となります。&lt;/p&gt;&lt;p&gt;ケースシーケンスや部分関数、PartialFunctionという用語は見慣れないかもしれませんが、プログラムをみれば、やろうとしていることは一目瞭然だと思います。まずは、match式の後ろ半分case句の集りがケースシーケンスで、ケースシーケンスはPartialFunctionという関数オブジェクトに落とし込まれる、と覚えておいてください。(使い方に慣れてきたら&lt;a href="http://www.scala-lang.org/docu/files/ScalaReference.pdf"&gt;文法書&lt;/a&gt;を確認して正確な定義を理解しておくとよいでしょう。)&lt;/p&gt;&lt;p&gt;PartialFunctionをScalaプログラムのリテラルとして記述する方法がケースシーケンスです。ケースシーケンスはmatch式からキーワードmatchを除いた後ろ半分の形です。今回のプログラムの以下の部分ですね。(アスタリスクは無視)&lt;/p&gt;&lt;pre name="code" class="java"&gt;******** {&lt;br /&gt;    case b if b &gt;= 0 =&gt; b.toString&lt;br /&gt;  }&lt;/pre&gt;&lt;p&gt;処理の意味はmatch式のcase句と同様です。指定されたInt値を変数bにバインドし、このbの値が0以上の場合は、Int値をStringに変換します。0以上の値でない場合は、この部分関数は未定義となります。部分関数が未定義の場合、Option#collectメソッドはNoneを返します。&lt;/p&gt;&lt;p&gt;PartialFunctionの主要なメソッドは以下の2つです。&lt;/p&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;メソッド&lt;/th&gt;&lt;th&gt;機能&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;isDefinedAt&lt;/td&gt;&lt;td&gt;指定された値が関数の引数として有効化を判定&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;apply&lt;/td&gt;&lt;td&gt;関数の評価&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;通常の関数オブジェクト(Function1など)はapplyメソッドは持っていますが、isDefinedAtは持っていません。&lt;/p&gt;&lt;p&gt;isDefinedAtメソッドは指定された値が関数に取って有効かどうかを判定するメソッドです。collectメソッドは、このisDefinedAtメソッドを使用して、現在扱っている値に対して部分関数が未定義がどうかを判定しているわけです。&lt;/p&gt;&lt;p&gt;前述のケースシーケンスの場合、case句中の「if b &gt;= 0」がisDefinedAtメソッドの実装に、「b.toString」がapplyメソッドの実装になるわけです。ケースシーケンスは、こういったPartialFunctionオブジェクト定義の文法糖衣というわけですね。&lt;/p&gt;&lt;p&gt;PartialFunctionはScalaプログラミングの様々な場所に現れ、非常に重要な役割を担います。これからも色々なイディオムに登場すると思います。&lt;/p&gt;&lt;div&gt;&lt;h5&gt;filter, collectの使い分け&lt;/h5&gt;&lt;p&gt;今回の用途では、filterメソッドとcollectメソッドはどちらも似たような効果を得ることができます。好みの方を使うとよいでしょう。&lt;/p&gt;&lt;p&gt;filterメソッドの方が機能が絞り込まれている分、プログラムがやりたいことの意図ははっきりすると思います。&lt;/p&gt;&lt;p&gt;ボク自身のプログラミングでは、多分collectメソッドの方を使うと思います。ちょっとだけ性能が速そうなので。&lt;/p&gt;&lt;p&gt;filterメソッドとcollectメソッドで明らかにcollectメソッドが有用なケースもあるのですが、これは別の機会に取り上げたいと思います。&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;諸元&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Scala 2.9.1&lt;/li&gt;&lt;li&gt;Scalaz 6.0.3&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7964484936470829118-5544458180265636706?l=modegramming.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://modegramming.blogspot.com/feeds/5544458180265636706/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://modegramming.blogspot.com/2012/02/scala-tips-option-5.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/5544458180265636706'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/5544458180265636706'/><link rel='alternate' type='text/html' href='http://modegramming.blogspot.com/2012/02/scala-tips-option-5.html' title='Scala Tips / Option (5)'/><author><name>asami</name><uri>http://www.blogger.com/profile/12083671403528595185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_4HtJQwbXqEY/S4sSwhKz5fI/AAAAAAAAAFs/IvXW6ca5RGE/S220/profile.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7964484936470829118.post-7842467988905220713</id><published>2012-01-31T08:00:00.000+09:00</published><updated>2012-01-31T08:00:02.427+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tips'/><category scheme='http://www.blogger.com/atom/ns#' term='scalaz'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>Scala Tips / Option (4)</title><content type='html'>&lt;div&gt;Optionから値を取り出すイディオムです。&lt;br /&gt;&lt;a href="http://modegramming.blogspot.com/2012/01/scala-tips-option-3.html"&gt;前回&lt;/a&gt;は、Optionに値が格納されているケースといないケースの両方に対応するイディオムでした。今回は、これを拡張してOptionに格納されている値が行おうとしている処理に対して無効だったケースを追加します。&lt;br /&gt;前回の演算は以下の表の示す演算でしたが、これを拡張して:&lt;br /&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;条件&lt;/th&gt;&lt;th&gt;結果&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Option[A]がSome[A]&lt;/td&gt;&lt;td&gt;Some[B]&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Option[A]がNone&lt;/td&gt;&lt;td&gt;None&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;以下の表が示す演算にします。&lt;br /&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;条件&lt;/th&gt;&lt;th&gt;結果&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Option[A]に有効な値が入っている&lt;/td&gt;&lt;td&gt;Some[B]&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Option[A]に無効な値が入っている&lt;/td&gt;&lt;td&gt;None&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Option[A]がNone&lt;/td&gt;&lt;td&gt;None&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;「Option[A]に無効な値が入っている」のケースが加わっています。&lt;br /&gt;以下では、引き続きOption[Int]からOption[String]への変換を例に考えてみます。ただし、Intは0以上のものが有効という条件を追加します。&lt;br /&gt;Optionに入っているIntが0以上の場合、Some[String]が処理結果となります。一方、0未満の場合は無効となりNoneが処理結果となります。&lt;br /&gt;(&lt;a href="http://modegramming.blogspot.com/2012/01/scala-tipsoption.html"&gt;分類の基準&lt;/a&gt;)&lt;br /&gt;&lt;div&gt;&lt;h4&gt;Java風&lt;/h4&gt;if式でOption#isDefinedを使ってOptionが有効であることを確認後、さらにif式で値が0以上であることを判定します。このプログラムにあるように &lt;code&gt;a.get&lt;/code&gt; を二度行なうか、&lt;code&gt;a.get&lt;/code&gt; の値を変数に覚えておかなくてはいけません。&lt;br /&gt;&lt;pre class="java" name="code"&gt;def f(a: Option[Int]): Option[String] = {&lt;br /&gt;&amp;nbsp; if (a.isDefined) {&lt;br /&gt;&amp;nbsp; &amp;nbsp; if (a.get &amp;gt;= 0) Some(a.get.toString)&lt;br /&gt;&amp;nbsp; &amp;nbsp; else None&lt;br /&gt;&amp;nbsp; } else {&lt;br /&gt;&amp;nbsp; &amp;nbsp; None&lt;br /&gt;&amp;nbsp; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;Scala風&lt;/h4&gt;match式を使うと以下のようになります。&lt;code&gt;a.get&lt;/code&gt; の二回判定(または &lt;code&gt;a.get&lt;/code&gt; の値を変数に記憶)が必要なくなるのでその点はすっきりしています。とはいえ「Noneの場合はNone」の処理を記述するのはScala的には悔しい感じ。&lt;br /&gt;&lt;pre class="java" name="code"&gt;def f(a: Option[Int]): Option[String] = {&lt;br /&gt;&amp;nbsp; a match {&lt;br /&gt;&amp;nbsp; &amp;nbsp; case Some(b) =&amp;gt; if (b &amp;gt;= 0) Some(b.toString) else None&lt;br /&gt;&amp;nbsp; &amp;nbsp; case None =&amp;gt; None&lt;br /&gt;&amp;nbsp; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;Scala&lt;/h4&gt;Scala的なコーディングでは、withFilterメソッドを使って、「0以上」という条件に合わない値の場合に、Some[A]からNoneへの切替えを行います。&lt;br /&gt;&lt;pre class="java" name="code"&gt;def f(a: Option[Int]): Option[String] = {&lt;br /&gt;&amp;nbsp; a.withFilter(_ &amp;gt;= 0).map(_.toString)&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;Scalaz&lt;/h4&gt;Scalaz流のエレガントな書き方はないと思います。&lt;/div&gt;&lt;div&gt;&lt;h4&gt;ノート&lt;/h4&gt;前回は以下の表の演算を行いましたが、今回はこれを拡張して:&lt;br /&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;条件&lt;/th&gt;&lt;th&gt;結果&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Option[A]がSome&lt;/td&gt;&lt;td&gt;Some[B]&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Option[A]がNone&lt;/td&gt;&lt;td&gt;None&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;以下の表の演算を行いました。&lt;br /&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;条件&lt;/th&gt;&lt;th&gt;結果&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Option[A]に有効な値が入っている&lt;/td&gt;&lt;td&gt;Some[B]&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Option[A]に無効な値が入っている&lt;/td&gt;&lt;td&gt;None&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Option[A]がNone&lt;/td&gt;&lt;td&gt;None&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;「Option[A]に無効な値が入っている」のケースが加わっていますが、この追加が何を意味しているのかというと、成功の文脈だったものをアプリケーションの意思で失敗の文脈に変えることができるということです。&lt;br /&gt;mapメソッドを使うと、成功の文脈における演算を記述することができましたが、成功の文脈を失敗の文脈に切り替えることはできませんでした。&lt;br /&gt;withFilterメソッドは、指定した条件が真の場合はSome[A]を返し、偽の場合はNoneを返します。また、Noneを受け取った場合はそのままNoneを返します。つまりwithFilterメソッドを使うことで、成功の文脈を失敗の文脈に切り替えることができるわけです。&lt;br /&gt;withFilterメソッドは以下の表の演算を行います。&lt;br /&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;条件&lt;/th&gt;&lt;th&gt;結果&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Option[A]に有効な値が入っている&lt;/td&gt;&lt;td&gt;Some[A]&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Option[A]に無効な値が入っている&lt;/td&gt;&lt;td&gt;None&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Option[A]がNone&lt;/td&gt;&lt;td&gt;None&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;また、mapメソッドは以下の表の演算を行います。&lt;br /&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;条件&lt;/th&gt;&lt;th&gt;結果&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Option[A]がSome[A]&lt;/td&gt;&lt;td&gt;Some[B]&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Option[A]がNone&lt;/td&gt;&lt;td&gt;None&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;この2つの表を連結すると以下の表になります。&lt;br /&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;条件&lt;/th&gt;&lt;th&gt;結果&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Option[A]に有効な値が入っている&lt;/td&gt;&lt;td&gt;Some[B]&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Option[A]に無効な値が入っている&lt;/td&gt;&lt;td&gt;None&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Option[A]がNone&lt;/td&gt;&lt;td&gt;None&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;以上のようにwithFilterメソッドとmapメソッド連結することで、全体として期待した結果が得られます。&lt;br /&gt;&lt;div&gt;&lt;h5&gt;withFilterとfilter&lt;/h5&gt;withFilterメソッドとほぼ同じ機能を持つfilterメソッドを使っても同じ結果が得られます。&lt;br /&gt;filterメソッドとwithFilterメソッドは、指定された条件でOptionの値をフィルタリングして、条件に合わない場合は成功の文脈(Some[A])から失敗の文脈(None)に切り替える点は同じです。&lt;br /&gt;異なるのは、filterメソッドはOption[A]を返すのに対して、withFilterメソッドはWithFilterというオブジェクトを返す点です。WithFilterオブジェクトは、mapメソッドなどつないでいく場合に利用するオブジェクトです。&lt;br /&gt;filterメソッドはメソッドチェインの最後に位置する場合に用いるのに対して、withFilterメソッドはメソッドチェインの内部にあり後続に別のメソッドがつながれる場合に使用します。メソッドチェインの最後に位置する場合は、Option[A]のオブジェクトを生成してこれを返すことになりますが、その後にすぐにmapメソッドなどがつながれる場合は、このOption[A]の生成が無駄になります。このような無駄を省くために用意されているのがwithFilterメソッドです。&lt;br /&gt;filterメソッドとwithFilterメソッドの使い分けがよく分からない場合は、filterメソッドを使っておくと安全です。ただし、若干ですが性能的に不利になります。&lt;br /&gt;filterメソッドとwithFilterメソッドには以上のような機能差があるため、Optionの値をフィルタした後にmapメソッドなどをつないでいく場合は、filterメソッドより高速に動作するwithFilterメソッドを使用するのがテクニックになっています。このためイディオムではwithFilterメソッドを採用しました。&lt;/div&gt;&lt;div&gt;&lt;h5&gt;collectメソッドとflatMapメソッド&lt;/h5&gt;Optionでは、filter/withFilterと同じような使い方ができるメソッドとしてcollect、filterNotが提供されています。&lt;br /&gt;filterNotメソッドはfilterメソッドと条件式が反対に作用するものです。&lt;br /&gt;collectメソッドは部分関数を用いて、Optionの値を変換しながら、成功の文脈と失敗の文脈の切り替えもできるという優れもののメソッドです。&lt;br /&gt;また、今回のイディオムはより汎用性の高いメソッドであるflatMapを用いて実現することもできます。&lt;br /&gt;collectメソッドとflatMapメソッドを使ったイディオムについて、続けて取り上げていきます。&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;諸元&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Scala 2.9.1&lt;/li&gt;&lt;li&gt;Scalaz 6.0.3&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7964484936470829118-7842467988905220713?l=modegramming.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://modegramming.blogspot.com/feeds/7842467988905220713/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://modegramming.blogspot.com/2012/01/scala-tips-option-4.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/7842467988905220713'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/7842467988905220713'/><link rel='alternate' type='text/html' href='http://modegramming.blogspot.com/2012/01/scala-tips-option-4.html' title='Scala Tips / Option (4)'/><author><name>asami</name><uri>http://www.blogger.com/profile/12083671403528595185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_4HtJQwbXqEY/S4sSwhKz5fI/AAAAAAAAAFs/IvXW6ca5RGE/S220/profile.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7964484936470829118.post-3113589636888299667</id><published>2012-01-30T08:00:00.000+09:00</published><updated>2012-01-30T08:00:00.793+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='smartdox'/><title type='text'>SmartDox 0.2.1 / クラス図の生成埋込み</title><content type='html'>&lt;div&gt;SmartDox 0.2.1をリリースしました。&lt;br /&gt;SimpleModelerを使って、CSVからクラス図の画像生成と埋込みができるようになりました。&lt;br /&gt;&lt;div&gt;&lt;h4&gt;機能&lt;/h4&gt;SmartDox 0.2.1では以下のオプションを提供しています。&lt;br /&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;オプション&lt;/th&gt;&lt;th&gt;機能&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;-html5&lt;/td&gt;&lt;td&gt;HTML5生成(試験的)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;-html4&lt;/td&gt;&lt;td&gt;HTML4生成&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;-html3&lt;/td&gt;&lt;td&gt;HTML3生成&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;-plain&lt;/td&gt;&lt;td&gt;プレインテキスト生成&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;-pdf&lt;/td&gt;&lt;td&gt;PDF生成&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;-latex&lt;/td&gt;&lt;td&gt;LaTeX生成&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;-blogger&lt;/td&gt;&lt;td&gt;Blogger用のHTML生成&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;基本的に&lt;a href="http://modegramming.blogspot.com/2012/01/smartdox-0.html"&gt;SmartDox 0.2&lt;/a&gt;と同じです。&lt;br /&gt;CSVで記述した情報からクラス図の画像を生成して、文書内に埋め込む機能をサポートしました。&lt;/div&gt;&lt;div&gt;&lt;h4&gt;サンプル&lt;/h4&gt;&lt;/div&gt;&lt;div&gt;SmartDox 0.2.1では以下のようなorg-mode文書が扱えます。&lt;br /&gt;&lt;pre class="java" name="code"&gt;#+TITLE: simplemodeler&lt;br /&gt;&lt;br /&gt;* SimpleModelerによるクラス図記述&lt;br /&gt;&lt;br /&gt;SimpleModelerを使ってCSVでクラス図を&lt;br /&gt;書くことができます。&lt;br /&gt;&lt;br /&gt;#+begin_sm_csv images/sm_csv_simplemodel.png&lt;br /&gt;#actor&lt;br /&gt;顧客&lt;br /&gt;個人顧客,,,,,顧客&lt;br /&gt;法人顧客,,,,,顧客&lt;br /&gt;#resource&lt;br /&gt;商品,商品名,,商品区分(第1類;第2類;第3類)&lt;br /&gt;#event&lt;br /&gt;購入する,,顧客;商品&lt;br /&gt;#+end_sm_csv&lt;br /&gt;&lt;/pre&gt;&lt;code&gt;#+begin_sm_csv images/sm_csv_simplemodel.png&lt;/code&gt; で始まるところがCSV言語で記述したクラス図情報です。この記述から自動的にクラス図の画像(png)を生成して文書に埋め込みます。&lt;br /&gt;この文章中にあるCSVからSmartDoxが(SimpleModeler経由で)生成するクラス図画像は以下のものです。&lt;br /&gt;&lt;div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-R3wjwSL_hxI/TyR8VHUL0CI/AAAAAAAAASA/XG--Z2-Yrw0/s1600/smcsvsimplemodel.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="320" src="http://4.bp.blogspot.com/-R3wjwSL_hxI/TyR8VHUL0CI/AAAAAAAAASA/XG--Z2-Yrw0/s320/smcsvsimplemodel.png" width="257" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;/div&gt;クラス図情報を記述するCSVの文法は次回に説明します。&lt;/div&gt;&lt;div&gt;&lt;h4&gt;PDF&lt;/h4&gt;クラス図画像の生成はHTMLやプレインテキストの生成時にも行いますが、ここではPDFを例にして生成されたクラス図画像がどのように文書中に埋め込まれるのかをみてみましょう。&lt;br /&gt;PDFの生成は以下のようにして行います。&lt;br /&gt;&lt;pre class="console"&gt;$ dox -plain sample.dox&lt;/pre&gt;2ページのPDFが生成されます。1ページ目はタイトルと目次ですが、2ページ目に以下のように生成されたクラス図が本文に埋め込まれています。&lt;br /&gt;&lt;div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-b-vJzZDYXiw/TyR8cp8Pk9I/AAAAAAAAASI/JcIqPJtQrWY/s1600/pdf2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="320" src="http://2.bp.blogspot.com/-b-vJzZDYXiw/TyR8cp8Pk9I/AAAAAAAAASI/JcIqPJtQrWY/s320/pdf2.png" width="255" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;h4&gt;インストール&lt;/h4&gt;プログラムの配布は、Scalaで最近注目されているconscriptを使っています。conscriptのインストール方法は以下のページに詳しいです。&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://blog.twiwt.org/e/58baf0"&gt;conscript - Scala で作られたソフトウェアをインストールするためのツール&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;Linux, Macであれば、以下のようにすればインストール完了です。&lt;br /&gt;&lt;pre class="console"&gt;$ curl https://raw.github.com/n8han/conscript/master/setup.sh | sh&lt;/pre&gt;conscriptをインストールした後、以下のようにしてSmartDoxをインストールします。&lt;br /&gt;&lt;pre class="console"&gt;$ cs asami/dox&lt;/pre&gt;以下の2つのコマンドがインストールされます。&lt;br /&gt;&lt;dl&gt;&lt;dt&gt;dox&lt;/dt&gt;&lt;dd&gt;SmartDoxコマンド&lt;/dd&gt;&lt;dt&gt;sdoc&lt;/dt&gt;&lt;dd&gt;SmartDocコマンド(互換用)&lt;/dd&gt;&lt;/dl&gt;&lt;div&gt;&lt;h5&gt;依存プロダクト&lt;/h5&gt;SmartDoxでは、以下のプロダクトに依存しています。&lt;br /&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;プロダクト&lt;/th&gt;&lt;th&gt;使用する機能&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;a href="http://www.latex-project.org/"&gt;LaTeX&lt;/a&gt;&lt;/td&gt;&lt;td&gt;PDF生成&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href="http://www.graphviz.org/"&gt;Graphviz&lt;/a&gt;&lt;/td&gt;&lt;td&gt;画像生成&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href="http://ditaa.sourceforge.net/"&gt;Ditaa&lt;/a&gt;&lt;/td&gt;&lt;td&gt;画像生成&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;プロダクトに依存する機能を使わない場合は必要ありません。&lt;br /&gt;&lt;div&gt;&lt;h6&gt;LaTeX&lt;/h6&gt;platexコマンドとdvipdfmxコマンドが実行可能になっていれば基本的にはOKです。&lt;br /&gt;Mac OS上でmacportsを使ってインストールしたLaTeXで動作確認しています。他の環境の場合、スタイルファイルなどがない可能性があります。&lt;/div&gt;&lt;div&gt;&lt;h6&gt;Graphviz&lt;/h6&gt;dotコマンドが実行可能になっていればOKです。&lt;br /&gt;Mac OS上でmacportsを使ってインストールしたGraphvizで動作確認しています。&lt;/div&gt;&lt;div&gt;&lt;h6&gt;Ditaa&lt;/h6&gt;ditaaコマンドが実行可能になっているか、&lt;i&gt;&lt;/i&gt;opt&lt;i&gt;&lt;/i&gt;local&lt;i&gt;&lt;/i&gt;share&lt;i&gt;&lt;/i&gt;java&lt;i&gt;&lt;/i&gt;ditaa0&lt;u&gt;&lt;/u&gt;9.jarのJarファイルが存在していればOKです。&lt;br /&gt;Mac OS上でmacportsを使ってDitaaをインストールすると、&lt;i&gt;&lt;/i&gt;opt&lt;i&gt;&lt;/i&gt;local&lt;i&gt;&lt;/i&gt;share&lt;i&gt;&lt;/i&gt;java&lt;i&gt;&lt;/i&gt;ditaa0&lt;u&gt;&lt;/u&gt;9.jarに配置されます。このditaa0&lt;u&gt;&lt;/u&gt;9.jarを決め打ちで使用しています。(いずれパラメタで指定可能にする予定です。)&lt;br /&gt;それ以外の環境では、シェルスクリプトなどでditaaコマンド(インストールされているJarファイルを呼び出す)を作成してください。&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;使い方&lt;/h4&gt;まだマニュアルがないので、文書フォーマットは&amp;nbsp;&lt;a href="http://orgmode.org/ja/index.html"&gt;org-mode&lt;/a&gt;を参考にしてください。あまり難しい文法を使わなければ大体大丈夫だと思います。&lt;br /&gt;org-mode形式で作成した文書から以下のようにしてHTMLやPDFに変換してください。&lt;br /&gt;&lt;pre class="console"&gt;$ dox -html4 mydoc.dox&lt;br /&gt;$ dox -pdf mydoc.dox&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7964484936470829118-3113589636888299667?l=modegramming.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://modegramming.blogspot.com/feeds/3113589636888299667/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://modegramming.blogspot.com/2012/01/smartdox-021.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/3113589636888299667'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/3113589636888299667'/><link rel='alternate' type='text/html' href='http://modegramming.blogspot.com/2012/01/smartdox-021.html' title='SmartDox 0.2.1 / クラス図の生成埋込み'/><author><name>asami</name><uri>http://www.blogger.com/profile/12083671403528595185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_4HtJQwbXqEY/S4sSwhKz5fI/AAAAAAAAAFs/IvXW6ca5RGE/S220/profile.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-R3wjwSL_hxI/TyR8VHUL0CI/AAAAAAAAASA/XG--Z2-Yrw0/s72-c/smcsvsimplemodel.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7964484936470829118.post-4484296204634910516</id><published>2012-01-27T08:00:00.000+09:00</published><updated>2012-01-27T08:00:05.195+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tips'/><category scheme='http://www.blogger.com/atom/ns#' term='scalaz'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>Scala Tips / Option (3)</title><content type='html'>&lt;div&gt;&lt;p&gt;Optionから値を取り出すイディオムです。&lt;/p&gt;&lt;p&gt;Optionの値を取り出すのは、Option#getメソッドを使うかパターンマッチングでSome(x)とするのが普通ですが、イディオムとして整理する場合は、適材適所という切り口が重要になるので、もう少し大きな粒度のシーケンスでまとめておきたいところです。&lt;/p&gt;&lt;p&gt;Optionから値を取り出す処理は以下の2つのコーディングパターンのいずれかの構成要素として使われることが多いでしょう。それぞれのケースについて考えていきます。&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Option［A］からOption［B］に変換&lt;/li&gt;&lt;li&gt;Option［A］からBに変換&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;まず、「Option［A］からOption［B］に変換」のイディオムです。Option［A］からOption［B］に変換するケースで注意が必要なのは、Option［A］がSome［A］ではなくNoneだったケースです。この場合は、AからBへの変換処理は行わずNoneにしなければなりません。これを表にまとめると以下のものになります。&lt;/p&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;条件&lt;/th&gt;&lt;th&gt;結果&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Option［A］がSome［A］&lt;/td&gt;&lt;td&gt;Some［B］&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Option［A］がNone&lt;/td&gt;&lt;td&gt;None&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;Optionから値を取るイディオムでは、Noneのケースも包含した形にしておく必要があるというわけです。&lt;/p&gt;&lt;p&gt;以下では、Option［Int］からOption［String］への変換を例に考えてみます。&lt;/p&gt;&lt;p&gt;(&lt;a href="http://modegramming.blogspot.com/2012/01/scala-tipsoption.html"&gt;分類の基準&lt;/a&gt;)&lt;/p&gt;&lt;div&gt;&lt;h4&gt;Java風&lt;/h4&gt;&lt;p&gt;if式でOption#isDefinedを使って値の有無を判定します。Option#isDefinedとOption#getが泣き別れになるので、あまりよい感触ではありません。&lt;/p&gt;&lt;pre name="code" class="java"&gt;def f(a: Option[Int]): Option[String] = {&lt;br /&gt;  if (a.isDefined) Some(a.get.toString)&lt;br /&gt;  else None&lt;br /&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;Scala風&lt;/h4&gt;&lt;p&gt;match式を使うと以下のようになります。こちらの方が綺麗ですね。&lt;/p&gt;&lt;pre name="code" class="java"&gt;def f(a: Option[Int]): Option[String] = {&lt;br /&gt;  a match {&lt;br /&gt;    case Some(b) =&gt; Some(b.toString)&lt;br /&gt;    case None =&gt; None&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;Scala&lt;/h4&gt;&lt;p&gt;Optionの処理にmapメソッドを使うのがScala的なコーディング。mapメソッド内に処理を記述します。(処理を行う関数を引数に指定します。)Noneの場合にはNoneになる、という処理はmapメソッド内で自動的に行ってくれるのがミソです。&lt;/p&gt;&lt;pre name="code" class="java"&gt;def f(a: Option[Int]): Option[String] = {&lt;br /&gt;  a.map(_.toString)&lt;br /&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;Scalaz&lt;/h4&gt;&lt;p&gt;Scalaz流のエレガントな書き方はないと思います。&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;ノート&lt;/h4&gt;&lt;p&gt;Optionの心は「成功/失敗の計算文脈」にあります。成功または失敗の状況を文脈として持ちまわるモナドという意味です。ボクが現時点で理解しているOptionの意味ですが、この言葉にピンと来ない場合もあまり気にする必要はありません。&lt;/p&gt;&lt;p&gt;実用的には、この抽象的な概念が具体的にどう役に立つのかという点が重要です。具体的に役に立つコーディングパターン、すなわちイディオムを洗いだしてマスターしておけばよいでしょう。&lt;/p&gt;&lt;p&gt;「成功/失敗の計算文脈」が具体的に何を指すのかという点について、前述した以下のmapメソッドを例に考えてみましょう。&lt;/p&gt;&lt;pre name="code" class="java"&gt;def f(a: Option[Int]): Option[String] = {&lt;br /&gt;  a.map(_.toString)&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;Option#mapメソッドは関数を引数に取りますが、成功の文脈(すなわちSome［Int］の場合)では関数を実行した結果(String)を再度Someに詰め直したもの(Some［String］)を返却値とします。Someに詰め直すということは値を更新しつつ、成功の文脈を引き継ぐということです。&lt;/p&gt;&lt;p&gt;一方、失敗の文脈(すなわちNoneの場合)は何もせず自動的にNoneを返却値とします。つまり、失敗の文脈の処理についてはプログラマは直接指定する必要はなく、Option側で自動的に行ってくれるということです。失敗の文脈が自動的に引き継がれる点は、Java風(if式を使う場合)やScala風(match式を使う場合)と比べてみると違いが明確です。&lt;/p&gt;&lt;p&gt;プログラマの関心が低い方の文脈である失敗の文脈が、Optionが内包しているロジックにより自動的に引き継がれるのがOptionの旨みで、Optionの実現技術であるモナドの威力です。&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7964484936470829118-4484296204634910516?l=modegramming.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://modegramming.blogspot.com/feeds/4484296204634910516/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://modegramming.blogspot.com/2012/01/scala-tips-option-3.html#comment-form' title='2 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/4484296204634910516'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/4484296204634910516'/><link rel='alternate' type='text/html' href='http://modegramming.blogspot.com/2012/01/scala-tips-option-3.html' title='Scala Tips / Option (3)'/><author><name>asami</name><uri>http://www.blogger.com/profile/12083671403528595185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_4HtJQwbXqEY/S4sSwhKz5fI/AAAAAAAAAFs/IvXW6ca5RGE/S220/profile.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7964484936470829118.post-405675468491604354</id><published>2012-01-26T08:00:00.000+09:00</published><updated>2012-01-26T08:00:03.475+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='simplemodeler'/><category scheme='http://www.blogger.com/atom/ns#' term='mindmapmodeling'/><title type='text'>「ソーシャルメディアマーケティングの基本戦略」のマインドマップとクラス図</title><content type='html'>&lt;div&gt;1月21日(土)に&lt;a href="http://ja-jp.facebook.com/groups/223587707726703/"&gt;横浜モデリング勉強会&lt;/a&gt;を行いました。また、会場には&lt;a href="http://www.atware.co.jp/"&gt;(株)アットウェア&lt;/a&gt;様の会議室をお借りしました。参加された皆さん、アットウェア様、どうもありがとうございました。懇親会では、勉強会でモデル駆動開発のハンズオンみたいなこともどうか、という意見もありました。そちらの方向への展開も考えてみたいと思います。&lt;br /&gt;この勉強会で、浅海が作成したモデルを紹介します。モデルは&lt;a href="http://www.amazon.co.jp/dp/479811748X"&gt;MindmapModeling&lt;/a&gt;の手法で作成しました。(&lt;a href="http://www.slideshare.net/asami224/mindmapmodeling"&gt;勉強会で使用したチュートリアル&lt;/a&gt;)&lt;br /&gt;モデリングの対象は、IT media エンタープライズ ビジネスイノベーション誌に掲載された小川浩氏の記事「&lt;a href="http://www.itmedia.co.jp/enterprise/articles/1002/02/news002.html"&gt;ソーシャルメディアマーケティングの基本戦略&lt;/a&gt; 」です。前回、前々回は経済ネタだったのですが、今回はITエンジニアにも親和性の高いソーシャルメディアのマーケッティングをテーマにしてみました。&lt;br /&gt;&lt;div&gt;&lt;h4&gt;単語を抜き出す&lt;/h4&gt;まず、最初の作業で記事中から単語を抜き出します。単語を抜き出しながら、登場人物、道具、出来事を中心にMindmapModelingの定めた分類に従って仕分けしていきます。&lt;br /&gt;この結果、できた最初のマインドマップが以下のものです。(以下、図をクリックすると拡大します。)&lt;br /&gt;&lt;div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-EAeMEOMZE6I/TyBz-HTSgII/AAAAAAAAARI/5nOzi61nlfo/s1600/xmind1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="400" src="http://2.bp.blogspot.com/-EAeMEOMZE6I/TyBz-HTSgII/AAAAAAAAARI/5nOzi61nlfo/s400/xmind1.png" width="362" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;/div&gt;記事の内容がソーシャルメディアマーケッティングの構造についてなので、そのあたりに単語が集中しています。&lt;/div&gt;&lt;div&gt;&lt;h4&gt;関係の洗練&lt;/h4&gt;次の段階では、抽出した、登場人物、道具、出来事の洗練を行います。用語の名寄せ、用語の種類(generalization)や部品構成(aggregation)を整理していきます。また、この段階で区分(powertype)の抽出を開始します。&lt;br /&gt;以上の作業を行った結果のマインドマップは以下のものです。&lt;br /&gt;&lt;div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-R1D4AvDkrJA/TyB0NNMQe-I/AAAAAAAAARQ/amyip9hwIlI/s1600/xmind2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="400" src="http://3.bp.blogspot.com/-R1D4AvDkrJA/TyB0NNMQe-I/AAAAAAAAARQ/amyip9hwIlI/s400/xmind2.png" width="362" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;/div&gt;&lt;a href="http://modegramming.blogspot.com/2011/12/xmind.html"&gt;SimpleModelerのサービス&lt;/a&gt;を使用して作成したクラス図は以下のものになります。&lt;br /&gt;&lt;div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-3UvMxFSPwf0/TyB0Vwj2SzI/AAAAAAAAARY/FFW1mgBgo6A/s1600/socialmarketing2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="70" src="http://3.bp.blogspot.com/-3UvMxFSPwf0/TyB0Vwj2SzI/AAAAAAAAARY/FFW1mgBgo6A/s400/socialmarketing2.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;/div&gt;今回は、ソーシャルメディアマーケッティングについての区分を整理を中心に作業しました。自然言語の文章としては意味が通っても、モデルの用語としては曖昧なところが出てくるのでそういった点を補ったり、MECE(Mutually Exclusive and Collectivily Exhausitive、もれなくだぶりなく)を念頭に区分の中身を整理しました。&lt;/div&gt;&lt;div&gt;&lt;h4&gt;出来事と物語&lt;/h4&gt;次の段階では、対象となる世界の動的な側面を捉える出来事や物語を整理していきます。出来事や物語を洗練していくことによって、出来事や物語における登場人物や道具の役割が明確化され、より登場人物や道具の構造をさらに洗練させることができます。出来事や物語で抽出した役割は、役割(role)としてモデル化して「役割」構造枝に配置し、役割の持つ構造を洗練していきます。&lt;br /&gt;&lt;div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-1cHvlpebhK8/TyB0f5Bs2OI/AAAAAAAAARg/fQO80kGbRM0/s1600/xmind3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="400" src="http://3.bp.blogspot.com/-1cHvlpebhK8/TyB0f5Bs2OI/AAAAAAAAARg/fQO80kGbRM0/s400/xmind3.png" width="337" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;/div&gt;&lt;a href="http://modegramming.blogspot.com/2011/12/xmind.html"&gt;SimpleModelerのサービス&lt;/a&gt;を使用して作成したクラス図は以下のものになります。&lt;br /&gt;&lt;div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-gH1MidnMpko/TyB0oLEXoeI/AAAAAAAAARo/whCTH_mWPNI/s1600/socialmarketing3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="70" src="http://3.bp.blogspot.com/-gH1MidnMpko/TyB0oLEXoeI/AAAAAAAAARo/whCTH_mWPNI/s400/socialmarketing3.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;/div&gt;今回は、よい物語が思い浮かばなかったので、出来事と規則を中心に洗練を進めました。&lt;br /&gt;また、ソーシャルメディアマーケッティングの手法として、記事中で明示的に列挙してあった(1)ペイパーポスト、(2)クチコミを分析、(3)情報発信だけでなく、記事中の他の場所にばらばらに書いてあった(4)コールセンター、(5)対面販売、(6)イベント応募も加えています。&lt;br /&gt;このように著者が形式知として明示したものにも案外抜けがあるものです。これを記事中から拾い集めてきて形式知化し、情報の再構成を行うのがMindmapModelingの目的です。&lt;br /&gt;以上が勉強会での作業です。&lt;/div&gt;&lt;div&gt;&lt;h4&gt;仕上げ&lt;/h4&gt;最後にドメインモデルの形に仕上げることにしましょう。&lt;a href="http://code.google.com/p/simplemodeler/"&gt;SimpleModeler&lt;/a&gt;を使用して作成したクラス図を見ながら調整していきます。&lt;br /&gt;ついでなのでSimpleModelerの機能を拡張して、より適切なクラス図が表示されるようにしてみました。来週ぐらいに&lt;a href="http://modegramming.blogspot.com/2011/12/xmind.html"&gt;SimpleModelerのサービス&lt;/a&gt;を新しいバージョンのSimpleModelerにアップグレードしたいと思います。&lt;br /&gt;以上の作業で作成したマインドマップとクラス図は以下のものになります。&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-oHh2azyIi_Y/TyB1Mf0DXLI/AAAAAAAAARw/Pz-fRbiizt4/s1600/final.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="400" src="http://1.bp.blogspot.com/-oHh2azyIi_Y/TyB1Mf0DXLI/AAAAAAAAARw/Pz-fRbiizt4/s400/final.png" width="332" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-f5ggX8vKrDg/TyB1OlOxcGI/AAAAAAAAAR4/o_hOPx7vMEg/s1600/socialmarketingfinal.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="147" src="http://1.bp.blogspot.com/-f5ggX8vKrDg/TyB1OlOxcGI/AAAAAAAAAR4/o_hOPx7vMEg/s400/socialmarketingfinal.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;かなりドメインモデルとして整理されました。ドメインモデルがこのレベルの情報を持つようになると、クラス図ベースでモデルの推敲をはじめても大丈夫です。&lt;br /&gt;生成されたクラス図をみてみると、たとえば「市場シェアが二番手、三番手の企業が大域的な市場シェアを奪うためにソーシャルマーケティングを行う」という物語(Business UseCase)を作成し、この物語を軸にモデルの精度をあげると面白いのではないか、とか色々とイメージが湧いてきますね。&lt;br /&gt;初見のモデリングでは、推敲のベースとなる初期モデルを作るのがなかなか大変なので、MindmapModeling→クラス図のアプローチはなかなか有力ではないかと思います。&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7964484936470829118-405675468491604354?l=modegramming.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://modegramming.blogspot.com/feeds/405675468491604354/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://modegramming.blogspot.com/2012/01/blog-post.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/405675468491604354'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/405675468491604354'/><link rel='alternate' type='text/html' href='http://modegramming.blogspot.com/2012/01/blog-post.html' title='「ソーシャルメディアマーケティングの基本戦略」のマインドマップとクラス図'/><author><name>asami</name><uri>http://www.blogger.com/profile/12083671403528595185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_4HtJQwbXqEY/S4sSwhKz5fI/AAAAAAAAAFs/IvXW6ca5RGE/S220/profile.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-EAeMEOMZE6I/TyBz-HTSgII/AAAAAAAAARI/5nOzi61nlfo/s72-c/xmind1.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7964484936470829118.post-1124731099206484766</id><published>2012-01-25T08:00:00.000+09:00</published><updated>2012-01-25T09:18:35.228+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tips'/><category scheme='http://www.blogger.com/atom/ns#' term='scalaz'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>Scala Tips / null</title><content type='html'>&lt;div&gt;&lt;p&gt;null値の可能性がある値をnull値ではない普通の値に持ち上げるイディオムです。&lt;/p&gt;&lt;p&gt;(&lt;a href="http://modegramming.blogspot.com/2012/01/scala-tipsoption.html"&gt;分類の基準&lt;/a&gt;)&lt;/p&gt;&lt;div&gt;&lt;h4&gt;Java風&lt;/h4&gt;&lt;p&gt;if式で変数がnullかどうかを判定します。&lt;/p&gt;&lt;pre name="code" class="java"&gt;def f(a: String, b: String): String = {&lt;br /&gt;  if (a == null) b&lt;br /&gt;  else a&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;実際に使う時は以下のような感じになります。&lt;/p&gt;&lt;pre name="code" class="java"&gt;val c = if (a == null) b else a&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;Scala風&lt;/h4&gt;&lt;p&gt;match式を使う時は以下のようになります。この場合は、Java風の方が簡潔ですね。&lt;/p&gt;&lt;pre name="code" class="java"&gt;def f(a: String, b: String): String = {&lt;br /&gt;  a match {&lt;br /&gt;    case null =&gt; b&lt;br /&gt;    case _ =&gt; a&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;Scala&lt;/h4&gt;&lt;p&gt;OptionとOption#getOrElseを使うと簡潔に記述できます。&lt;/p&gt;&lt;pre name="code" class="java"&gt;def f(a: String, b: String): String = {&lt;br /&gt;  Option(a) getOrElse b&lt;br /&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;Scalaz&lt;/h4&gt;&lt;p&gt;Scalazを使うと、さらに簡潔に記述することができます。&lt;/p&gt;&lt;pre name="code" class="java"&gt;def f(a: String, b: String): String = {&lt;br /&gt;  a ?? b&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;以下のような形でメソッドの引数に書きたい場合は、"??"を使った簡潔な記述方法は重宝します。&lt;/p&gt;&lt;pre name="code" class="java"&gt;val a = SomeJavaObject.getStringValue()&lt;br /&gt;println("Value is " + a ?? "unknown")&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;ノート&lt;/h4&gt;&lt;p&gt;プログラムの実行速度という観点では、「Java風」が一番速く、「Scala」はオブジェクト生成とメソッド呼出しが余分に発生するためかなり遅くなります。「Scalaz」は、さらに一段余分にオブジェクト生成とメソッド呼出しが発生するため、さらに低速です。&lt;/p&gt;&lt;p&gt;つまり、Javaの実行速度とScalaの記述力のトレードオフが発生するわけです。実行速度を採るのであればJavaで書けばよいので、Scalaで書く以上、簡潔に記述できることを重視するのがよいでしょう。&lt;/p&gt;&lt;p&gt;まずScalaで書いてみて、プロファイルでホットスポットと判明した処理については、Java風に書き直したり、Java(場合によってはC++)で書いて呼び出すというアプローチになります。&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7964484936470829118-1124731099206484766?l=modegramming.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://modegramming.blogspot.com/feeds/1124731099206484766/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://modegramming.blogspot.com/2012/01/scala-tips-null.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/1124731099206484766'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/1124731099206484766'/><link rel='alternate' type='text/html' href='http://modegramming.blogspot.com/2012/01/scala-tips-null.html' title='Scala Tips / null'/><author><name>asami</name><uri>http://www.blogger.com/profile/12083671403528595185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_4HtJQwbXqEY/S4sSwhKz5fI/AAAAAAAAAFs/IvXW6ca5RGE/S220/profile.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7964484936470829118.post-5163212588110775387</id><published>2012-01-24T08:00:00.000+09:00</published><updated>2012-01-24T08:00:04.277+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tips'/><category scheme='http://www.blogger.com/atom/ns#' term='scalaz'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>Scala Tips / Option (2)</title><content type='html'>&lt;div&gt;&lt;p&gt;null値の可能性がある値をOptionに持ち上げるイディオムです。&lt;/p&gt;&lt;p&gt;Scalaでは、できるだけnull値を使わないようにするのが、プログラミングのコツになっています。そのため、既存のJavaプログラムから戻ってきた値などを速やかにOptionに持ち上げる、といった処理がよく出てきます。この処理を簡潔に書けるイディオムを覚えておくとプログラミングがスムーズになります。&lt;/p&gt;&lt;p&gt;(&lt;a href="http://modegramming.blogspot.com/2012/01/scala-tipsoption.html"&gt;分類の基準&lt;/a&gt;)&lt;/p&gt;&lt;div&gt;&lt;h4&gt;Java風&lt;/h4&gt;&lt;p&gt;if式で変数がnullかどうかを判定します。&lt;/p&gt;&lt;pre name="code" class="java"&gt;def f(a: String): Option[String] = {&lt;br /&gt;  if (a == null) None&lt;br /&gt;  else Some(a)&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;実際に使う時は以下のような感じになります。&lt;/p&gt;&lt;pre name="code" class="java"&gt;val b = if (a == null) None else Some(a)&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;Scala風&lt;/h4&gt;&lt;p&gt;match式を使うこ以下のようになります。この場合は、Java風の方が簡潔ですね。&lt;/p&gt;&lt;pre name="code" class="java"&gt;def f(a: String): Option[String] = {&lt;br /&gt;  a match {&lt;br /&gt;    case null =&gt; None&lt;br /&gt;    case _ =&gt; Some(a)&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;Scala&lt;/h4&gt;&lt;p&gt;Optionオブジェクトに目的にぴったりあうメソッドapplyがあるので、これを使うのがイディオム。Option(a)は、Optionオブジェクトのapplyメソッドを呼び出す簡略記法です。&lt;/p&gt;&lt;pre name="code" class="java"&gt;def f(a: String): Option[String] = {&lt;br /&gt;  Option(a)&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;Optionの持つ基本機能なのでイディオムというのも大げさですが、ボクも長年この使い方を知らずに損なコーディングをしていたので、イディオムとしてまとめておきました。(Scala 2.8でサポートされた機能のようです。)&lt;/p&gt;&lt;p&gt;パッと見は &lt;code&gt;Option(null)&lt;/code&gt; とすると &lt;code&gt;Some(null)&lt;/code&gt; が返ってきそうですが、&lt;code&gt;None&lt;/code&gt; が返って来てくれるということですね。&lt;code&gt;Some(null)&lt;/code&gt; が欲しい場合には、文字通り &lt;code&gt;Some(null)&lt;/code&gt; とします。&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;Scalaz&lt;/h4&gt;&lt;p&gt;Scalaz流のエレガントな書き方はないと思います。&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;利用シーン&lt;/h4&gt;&lt;p&gt;Scalaでnullを使いたいユースケースとして、メソッドのデフォルト値があります。(いずれイディオムとして取り上げたいと思います。)&lt;/p&gt;&lt;pre name="code" class="java"&gt;case class Person(name: String, address: Option[String])&lt;br /&gt;&lt;br /&gt;object Person {&lt;br /&gt;  def apply(name: String, address: String = null) = {&lt;br /&gt;    new Person(name, Option(address))&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;ここを以下のようにしたくないということですね。&lt;/p&gt;&lt;pre name="code" class="java"&gt;new Person(name, if (address == null) None else Some(address))&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7964484936470829118-5163212588110775387?l=modegramming.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://modegramming.blogspot.com/feeds/5163212588110775387/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://modegramming.blogspot.com/2012/01/scala-tips-option-2.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/5163212588110775387'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/5163212588110775387'/><link rel='alternate' type='text/html' href='http://modegramming.blogspot.com/2012/01/scala-tips-option-2.html' title='Scala Tips / Option (2)'/><author><name>asami</name><uri>http://www.blogger.com/profile/12083671403528595185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_4HtJQwbXqEY/S4sSwhKz5fI/AAAAAAAAAFs/IvXW6ca5RGE/S220/profile.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7964484936470829118.post-8089540570232727172</id><published>2012-01-23T08:00:00.000+09:00</published><updated>2012-01-23T11:57:26.652+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='smartdox'/><title type='text'>SmartDox 0.2</title><content type='html'>&lt;div&gt;SmartDox 0.2をリリースしました。&lt;br /&gt;PDF、プレインテキスト、HTML4の生成をサポートしました。また、GraphvizやDitaaを使った画像の生成と埋込みもできるようになりました。&lt;br /&gt;エラー処理などがまだ柔らかいですが、ある程度使えるレベルのものになってきたと思います。&lt;br /&gt;&lt;div&gt;&lt;h4&gt;機能&lt;/h4&gt;SmartDox 0.2では以下のオプションを提供しました。&lt;br /&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;オプション&lt;/th&gt;&lt;th&gt;機能&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;-html5&lt;/td&gt;&lt;td&gt;HTML5生成(試験的)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;-html4&lt;/td&gt;&lt;td&gt;HTML4生成&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;-html3&lt;/td&gt;&lt;td&gt;HTML3生成&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;-plain&lt;/td&gt;&lt;td&gt;プレインテキスト生成&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;-pdf&lt;/td&gt;&lt;td&gt;PDF生成&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;-latex&lt;/td&gt;&lt;td&gt;LaTeX生成&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;-blogger&lt;/td&gt;&lt;td&gt;Blogger用のHTML生成&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;html4, html3, plain, pdf, latexはSmartDocのエンジンを使用しています。&lt;br /&gt;html5とbloggerはSmartDoxで新規に開発を進めたものです。&lt;br /&gt;html5は試験的な簡単な実装の段階です。&lt;br /&gt;bloggerは、このブログでも使用しているBloggerでブログを書くときに使用するHTMLを生成します。生成したHTMLをBloggerのHTMLエディタに手動で貼り付けて使用します。&lt;a href="http://modegramming.blogspot.com/2012/01/scala-tipsoption.html"&gt;前回のエントリ&lt;/a&gt;から、このbloggerオプションを使用しています。&lt;br /&gt;また、Dot言語(Graphviz)とDitaa言語で記述した画像を生成して、文書内に埋め込む機能をサポートしました。&lt;/div&gt;&lt;div&gt;&lt;h4&gt;インストール&lt;/h4&gt;プログラムの配布は、Scalaで最近注目されているconscriptを使っています。conscriptのインストール方法は以下のページに詳しいです。&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://blog.twiwt.org/e/58baf0"&gt;conscript - Scala で作られたソフトウェアをインストールするためのツール&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;Linux, Macであれば、以下のようにすればインストール完了です。&lt;br /&gt;&lt;pre class="console"&gt;$ curl https://raw.github.com/n8han/conscript/master/setup.sh | sh&lt;/pre&gt;conscriptをインストールした後、以下のようにしてSmartDoxをインストールします。&lt;br /&gt;&lt;pre class="console"&gt;$ cs asami/dox&lt;/pre&gt;以下の2つのコマンドがインストールされます。&lt;br /&gt;&lt;dl&gt;&lt;dt&gt;dox&lt;/dt&gt;&lt;dd&gt;SmartDoxコマンド&lt;/dd&gt;&lt;dt&gt;sdoc&lt;/dt&gt;&lt;dd&gt;SmartDocコマンド(互換用)&lt;/dd&gt;&lt;/dl&gt;&lt;div&gt;&lt;h5&gt;依存プロダクト&lt;/h5&gt;SmartDoxでは、以下のプロダクトに依存しています。&lt;br /&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;プロダクト&lt;/th&gt;&lt;th&gt;使用する機能&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;a href="http://www.latex-project.org/"&gt;LaTeX&lt;/a&gt;&lt;/td&gt;&lt;td&gt;PDF生成&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href="http://www.graphviz.org/"&gt;Graphviz&lt;/a&gt;&lt;/td&gt;&lt;td&gt;Dot言語画像生成&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href="http://ditaa.sourceforge.net/"&gt;Ditaa&lt;/a&gt;&lt;/td&gt;&lt;td&gt;Ditaa言語画像生成&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;プロダクトに依存する機能を使わない場合は必要ありません。&lt;br /&gt;&lt;div&gt;&lt;h6&gt;LaTeX&lt;/h6&gt;platexコマンドとdvipdfmxコマンドが実行可能になっていれば基本的にはOKです。&lt;br /&gt;Mac OS上でmacportsを使ってインストールしたLaTeXで動作確認しています。他の環境の場合、スタイルファイルなどがない可能性があります。&lt;/div&gt;&lt;div&gt;&lt;h6&gt;Graphviz&lt;/h6&gt;dotコマンドが実行可能になっていればOKです。&lt;br /&gt;Mac OS上でmacportsを使ってインストールしたGraphvizで動作確認しています。&lt;/div&gt;&lt;div&gt;&lt;h6&gt;Ditaa&lt;/h6&gt;ditaaコマンドが実行可能になっているか、/opt/local/share/java/ditaa0_9.jarのJarファイルが存在していればOKです。&lt;br /&gt;Mac OS上でmacportsを使ってDitaaをインストールすると、/opt/local/share/java/ditaa0_9.jarに配置されます。このditaa0_9.jarを決め打ちで使用しています。(いずれパラメタで指定可能にする予定です。)&lt;br /&gt;それ以外の環境では、シェルスクリプトなどでditaaコマンド(インストールされているJarファイルを呼び出す)を作成してください。&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;使い方&lt;/h4&gt;まだマニュアルがないので、文書フォーマットは &lt;a href="http://orgmode.org/ja/index.html"&gt;org-mode&lt;/a&gt;を参考にしてください。あまり難しい文法を使わなければ大体大丈夫だと思います。&lt;br /&gt;org-mode形式で作成した文書から以下のようにしてHTMLやPDFに変換してください。&lt;br /&gt;&lt;pre class="console"&gt;$ dox -html4 mydoc.dox&lt;br /&gt;$ dox -pdf mydoc.dox&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;サンプル&lt;/h4&gt;SmartDox 0.2では以下のようなorg-mode文書が扱えます。&lt;br /&gt;&lt;pre class="java" name="code"&gt;#+title: SmartDoxサンプル&lt;br /&gt;#+author: 浅海&lt;br /&gt;#+date: 2012年1月22日&lt;br /&gt;&lt;br /&gt;* 文章&lt;br /&gt;&lt;br /&gt;これは *SmartDox* の文章です。&lt;br /&gt;&lt;br /&gt;- SmartDoxのコンセプトは(org-mode＋html5)／2&lt;br /&gt;- HTMLに加えてPDFやプレインテキストを生成することができます。&lt;br /&gt;- GraphvizやDitaaの画像を生成して埋め込むことができます。&lt;br /&gt;&lt;br /&gt;* 表&lt;br /&gt;&lt;br /&gt;| オプション | 機能                 |&lt;br /&gt;|------------+----------------------|&lt;br /&gt;| -html5     | HTML5生成(試験的)    |&lt;br /&gt;| -html4     | HTML4生成            |&lt;br /&gt;| -html3     | HTML3生成            |&lt;br /&gt;| -plain     | プレインテキスト生成 |&lt;br /&gt;| -pdf       | PDF生成              |&lt;br /&gt;| -latex     | LaTeX生成            |&lt;br /&gt;| -blogger   | Blogger用のHTML生成  |&lt;br /&gt;&lt;br /&gt;* 画像&lt;br /&gt;&lt;br /&gt;** graphviz&lt;br /&gt;&lt;br /&gt;[[http://www.graphviz.org/][Graphviz]] の図を直接書くことができます。&lt;br /&gt;&lt;br /&gt;#+begin_dot images/dot_example.png -Tpng&lt;br /&gt;digraph G {&lt;br /&gt;  Hello-&amp;gt;World&lt;br /&gt;}&lt;br /&gt;#+end_dot&lt;br /&gt;&lt;br /&gt;** ditaa&lt;br /&gt;&lt;br /&gt;[[http://ditaa.sourceforge.net/][Ditaa]] の図を直接書くことができます。&lt;br /&gt;&lt;br /&gt;#+begin_ditaa images/ditaa_example.png&lt;br /&gt;+--------+   +-------+    +-------+&lt;br /&gt;|        | --+ ditaa +--&amp;gt; |       |&lt;br /&gt;|  Text  |   +-------+    |diagram|&lt;br /&gt;|Document|   |!magic!|    |       |&lt;br /&gt;|     {d}|   |       |    |       |&lt;br /&gt;+---+----+   +-------+    +-------+&lt;br /&gt;    :                         ^&lt;br /&gt;    |       Lots of work      |&lt;br /&gt;    +-------------------------+&lt;br /&gt;#+end_ditaa&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;「#+begin_dot images/dot_example.png -Tpng」で始まるところがGraphviz言語で記述した画像、「#+begin_ditaa images/ditaa_example.png」で始まるところがDitaa言語で記述した画像です。この記述から自動的に画像(png)を生成して文書に埋め込みます。&lt;/div&gt;&lt;div&gt;&lt;h4&gt;PDF&lt;/h4&gt;PDFの生成は以下のようにして行います。&lt;br /&gt;&lt;pre class="console"&gt;$ dox -plain sample.dox&lt;/pre&gt;以下の3つのページから構成されるPDFが生成されます。&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-ajE5r4p_vlo/TxyPpoBlEJI/AAAAAAAAAQc/ryZK5B9Vifk/s1600/pdf1.png" imageanchor="1"&gt;&lt;img border="0" height="320" src="http://2.bp.blogspot.com/-ajE5r4p_vlo/TxyPpoBlEJI/AAAAAAAAAQc/ryZK5B9Vifk/s320/pdf1.png" width="255" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-XYAnWLm_RG0/TxyPqD-OECI/AAAAAAAAAQo/NKoLDEUrI3A/s1600/pdf2.png" imageanchor="1"&gt;&lt;img border="0" height="320" src="http://1.bp.blogspot.com/-XYAnWLm_RG0/TxyPqD-OECI/AAAAAAAAAQo/NKoLDEUrI3A/s320/pdf2.png" width="255" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-9mwVLp1qLIE/TxyPqpEDWTI/AAAAAAAAAQ0/xAgSLF2t5is/s1600/pdf3.png" imageanchor="1"&gt;&lt;img border="0" height="320" src="http://4.bp.blogspot.com/-9mwVLp1qLIE/TxyPqpEDWTI/AAAAAAAAAQ0/xAgSLF2t5is/s320/pdf3.png" width="255" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;プレインテキスト　&lt;/h4&gt;プレインテキストの生成は以下のようにして行います。&lt;br /&gt;&lt;pre class="console"&gt;$ dox -plain sample.dox&lt;/pre&gt;以下のプレインテキストが生成されます。&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-hnExYLG4_18/TxyPq9IE25I/AAAAAAAAARA/znRLwJgCBSs/s1600/plaintext.png" imageanchor="1"&gt;&lt;img border="0" height="320" src="http://2.bp.blogspot.com/-hnExYLG4_18/TxyPq9IE25I/AAAAAAAAARA/znRLwJgCBSs/s320/plaintext.png" width="163" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7964484936470829118-8089540570232727172?l=modegramming.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://modegramming.blogspot.com/feeds/8089540570232727172/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://modegramming.blogspot.com/2012/01/smartdox-0.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/8089540570232727172'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/8089540570232727172'/><link rel='alternate' type='text/html' href='http://modegramming.blogspot.com/2012/01/smartdox-0.html' title='SmartDox 0.2'/><author><name>asami</name><uri>http://www.blogger.com/profile/12083671403528595185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_4HtJQwbXqEY/S4sSwhKz5fI/AAAAAAAAAFs/IvXW6ca5RGE/S220/profile.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-ajE5r4p_vlo/TxyPpoBlEJI/AAAAAAAAAQc/ryZK5B9Vifk/s72-c/pdf1.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7964484936470829118.post-6885665036728424759</id><published>2012-01-20T22:59:00.000+09:00</published><updated>2012-01-20T22:59:49.364+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tips'/><category scheme='http://www.blogger.com/atom/ns#' term='scalaz'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>Scala Tips/Option</title><content type='html'>&lt;div&gt;&lt;p&gt;プログラミング言語の習得で重要なことの一つは、局面ごとに使うイディオムを体で覚えて無意識に出てくるようにすることです。&lt;/p&gt;&lt;p&gt;Scalaでのイディオムも少し見えてきたので、少しずつ整理していきたいと思います。&lt;/p&gt;&lt;p&gt;基本文法を覚えたての知識でのコーディングからScalazまでを併置するようにしました。以下のような分類にしています。&lt;/p&gt;&lt;dl&gt;&lt;dt&gt;Java風&lt;/dt&gt;&lt;dd&gt;Javaプログラミングの感覚でコーディングしたもの&lt;/dd&gt;&lt;dt&gt;Scala風&lt;/dt&gt;&lt;dd&gt;Scalaらしい文法を使っているが、少し泥臭い感じ&lt;/dd&gt;&lt;dt&gt;Scala&lt;/dt&gt;&lt;dd&gt;Scalaでのイディオム&lt;/dd&gt;&lt;dt&gt;Scalaz&lt;/dt&gt;&lt;dd&gt;Scalazでのイディオム&lt;/dd&gt;&lt;/dl&gt;&lt;p&gt;Java風、Scala風は問題を明確にするための参考情報で、ScalaまたはScalazが推奨の方法です。&lt;/p&gt;&lt;p&gt;今回は、Optionから値を取り出す時に、Noneの場合デフォルト値を使用する方法です。&lt;/p&gt;&lt;div&gt;&lt;h4&gt;Java風&lt;/h4&gt;&lt;p&gt;if式でOptionのisDefinedメソッドを判定します。安全確実ですが、if式、Option#isDefined、Option#getが出てきたら、Scala的にはちょっと負けっぽい。&lt;/p&gt;&lt;p&gt;Option#isDefinedとOption#getが何かの拍子で泣き別れになるとバグの元になるので、この組合せはできるだけ避けたいわけです。&lt;/p&gt;&lt;pre name="code" class="java"&gt;def f(a: Option[Int]): Int = {&lt;br /&gt;  if (a.isDefined) a.get&lt;br /&gt;  else 0&lt;br /&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;Scala風&lt;/h4&gt;&lt;p&gt;match式を使うことで、if式、Option#isDefined、Option#getが見えなくなりました。ただ、やろうとしていることに対して記述がやや冗長な感触です。&lt;/p&gt;&lt;pre name="code" class="java"&gt;def f(a: Option[Int]): Int = {&lt;br /&gt;  a match {&lt;br /&gt;    case Some(b) =&gt; b&lt;br /&gt;    case None =&gt; 0&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;Scala&lt;/h4&gt;&lt;p&gt;Optionに目的にぴったりあうメソッドgetOrElseがあるので、これを使うのがイディオム。事前に用意されているメソッドを使うだけなのでイディオムと呼ぶのはやや大げさですが、ユースケースに対する解を、考えて分かるのではなく、無意識に出てくるのが大事なので、イディオムとして取り上げています。&lt;/p&gt;&lt;pre name="code" class="java"&gt;def f(a: Option[Int]): Int = {&lt;br /&gt;  a getOrElse 0&lt;br /&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;Scalaz&lt;/h4&gt;&lt;p&gt;Scalazの場合は"|"でデフォルト値をより簡潔に記述することができます。&lt;/p&gt;&lt;pre name="code" class="java"&gt;def f(a: Option[Int]): Int = {&lt;br /&gt;  a | 0&lt;br /&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7964484936470829118-6885665036728424759?l=modegramming.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://modegramming.blogspot.com/feeds/6885665036728424759/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://modegramming.blogspot.com/2012/01/scala-tipsoption.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/6885665036728424759'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/6885665036728424759'/><link rel='alternate' type='text/html' href='http://modegramming.blogspot.com/2012/01/scala-tipsoption.html' title='Scala Tips/Option'/><author><name>asami</name><uri>http://www.blogger.com/profile/12083671403528595185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_4HtJQwbXqEY/S4sSwhKz5fI/AAAAAAAAAFs/IvXW6ca5RGE/S220/profile.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7964484936470829118.post-6209869100336469509</id><published>2012-01-11T10:47:00.002+09:00</published><updated>2012-01-11T11:26:26.861+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='fp'/><category scheme='http://www.blogger.com/atom/ns#' term='ofp'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>SmartDoxの実装技術</title><content type='html'>昨日はSmartDoxの紹介をしましたが、今日はSmartDoxの実装技術について説明します。&lt;br /&gt;既存のプログラムの改良では、今まで積み上げてきたアーキテクチャや使っているフレームワークの関係があって、思い切ったコーディング方針の変更はなかなかできません。&lt;br /&gt;SmartDoxは新規開発なので、練習も兼ねてボクが認識している今風のScalaプログラミングを取り入れてみました。&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Scala&lt;/li&gt;&lt;li&gt;sbt&lt;/li&gt;&lt;li&gt;conscript&lt;/li&gt;&lt;li&gt;GitHub&lt;/li&gt;&lt;li&gt;関数型プログラミング&lt;/li&gt;&lt;li&gt;代数データ構造&lt;/li&gt;&lt;li&gt;Scalaz&lt;/li&gt;&lt;li&gt;パーサーコンビネータ&lt;/li&gt;&lt;/ul&gt;&lt;div class="outline-2" id="outline-container-1"&gt;&lt;h4 id="sec-1"&gt;Scala, sbt&lt;/h4&gt;&lt;div class="outline-text-2" id="text-1"&gt;実装言語Scala、ビルドツールsbtは現在の既定路線です。&lt;br /&gt;sbtは、後発だけあって何かと使いやすいのと、Scalaプログラミング特有の色々な事情をハンドリングしてくれるので、Scalaプログラミングでは必須です。&lt;br /&gt;たとえば、Scalaは、コンパイルしたScalaバージョンの異なるライブラリのバイナリ互換が鬼門で、JavaだとJARファイルがlibname-1.0.jarとなるところを、Scalaだとlibname&lt;sub&gt;2&lt;/sub&gt;.9.1-0.1.jarといった具合に使用するScalaライブラリのバージョン(2.9.1)をファイル名に埋め込むのが、基本的な運用になっていますが、sbtはこのあたりをうまくハンドリングしてくれます。&lt;br /&gt;編集、デバッグにはEclipseを使っていますが、sbtのEclipseプラグインで「.classpath」を生成して、ライブラリの依存性を取り込む運用にしています。&lt;br /&gt;ただし、sbtだけでは力不足のところもあります。以下の処理はsbtでやり方を見つけられなかったのでmavenとantを併用しています。&lt;br /&gt;&lt;ul&gt;&lt;li&gt;JavaのみのプロジェクトのJar作成(2.9.1を付けないJar名)&lt;/li&gt;&lt;li&gt;FTPによるmavenリポジトリへのアップロード(sftpならできるのですが、昔ながらのftpはダメみたい)&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="outline-2" id="outline-container-2"&gt;&lt;h4 id="sec-2"&gt;conscript&lt;/h4&gt;&lt;div class="outline-text-2" id="text-2"&gt;SmartDoxのインストールには&lt;a href="https://github.com/n8han/conscript"&gt;conscript&lt;/a&gt;を使いました。&lt;br /&gt;conscriptはGitHubに格納したアプリケーションの構成情報を使用して、アプリケーションの依存関係を解決した上でローカル環境にインストールしてくれるインストーラです。&lt;br /&gt;プログラムの提供側、利用者側のどちらもかなり便利なので、これから広く使われるようになるのではないかと思います。&lt;/div&gt;&lt;/div&gt;&lt;div class="outline-2" id="outline-container-3"&gt;&lt;h4 id="sec-3"&gt;GitHub&lt;/h4&gt;&lt;div class="outline-text-2" id="text-3"&gt;ソースコードの管理はGitHubを使っています。GitHubはUIが使いやすいので、このところ新規プログラムはGitHub上で開発していますが、SmartDoxの場合は、conscriptを使うというためという理由もあります。&lt;br /&gt;GitHubは、ソースコードのバージョン管理という枠組みを超えて、conscriptのような形でソフトウェアリポジトリ的な使われ方もしてきています。こういう新しい応用が出てくるので、使っていて刺激的ですね。&lt;/div&gt;&lt;/div&gt;&lt;div class="outline-2" id="outline-container-4"&gt;&lt;h4 id="sec-4"&gt;関数型プログラミング&lt;/h4&gt;&lt;div class="outline-text-2" id="text-4"&gt;関数型プログラミングは、ボクがLispをかじっていた頃(25年ぐらい前)はラムダ計算をベースに、List、クロージャといった部品を使ってプログラミングしていくものでしたが(さらにいうと綺麗につくると性能がでないので、手続き型的なプログラミングにしたり、nreverseといった破壊的な関数を使うのがバッドノウハウ)、現在は状況が一変しています。&lt;br /&gt;まずハードウェア性能の向上で、関数型言語の宿命だった動作性能は事実上あまり問題にならなくなっています。Javaを使って大丈夫な用途であればScalaでも基本的には大丈夫と考えてよいでしょう。RubyやPythonで大丈夫な用途であれば、Scalaだと逆に高速に動作しそうです。&lt;br /&gt;技術的には、モナド、型クラスという新しい技術が登場し、これが新しい関数型プログラミングの基盤になっています。&lt;br /&gt;ボクも2008年にScalaを始める前は、昔の関数型プログラミングのイメージで関数型言語を捉えていたのですが(List処理が便利で開発効率がアップとか)、現在では全く別物と考えています。モナド、型クラスはそれだけのインパクトのある技術ということが分かりました。いつの間にか、こんなことになっていたのか、という感じです。&lt;br /&gt;さらに、Scalaでは関数型プログラミング(FP)とオブジェクト指向プログラミング(OOP)の融合したObject-Functional Programming(OFP)という概念が提唱しています。&lt;br /&gt;歴史的な蓄積やOOADからの連続性を考えると、OOPは今後も軸の一つで在り続けることになると予想されます。ここにFPの記述力をどのように融合させていくのかということが、実務の世界では非常に重要になるのは明らかで、OFPはこれは今後大発展する分野と考えています。&lt;br /&gt;このあたりを意識しつつSmartDoxの開発では、今風のFP的な技術をできるだけ使うことにしました。&lt;/div&gt;&lt;/div&gt;&lt;div class="outline-2" id="outline-container-5"&gt;&lt;h4 id="sec-5"&gt;代数的データ型&lt;/h4&gt;&lt;div class="outline-text-2" id="text-5"&gt;まずデータ構造として、代数的データ型(Algebraic data type)を使用します。Scalaでは、代数的データ型は直接サポートされていませんが、case classがこの目的での利用を想定して提供されています。たとえば&lt;a href="http://www.scala-lang.org/docu/files/ScalaTutorial.pdf"&gt;A Scala Tutorial for Java programmers&lt;/a&gt;にも以下の記述があります。このあたりの背景は、&lt;a href="http://biblion.epfl.ch/EPFL/theses/2007/3899/EPFL_TH3899.pdf"&gt;Object-Oriented Pattern Matching&lt;/a&gt;に詳しいようです。&lt;br /&gt;&lt;pre class="example"&gt;In Java, such a tree would be represented using an abstract super-class for the trees,&lt;br /&gt;and one concrete sub-class per node or leaf. In a functional programming language,&lt;br /&gt;one would use an algebraic data-type for the same purpose. Scala provides the concept of case classes which is somewhat in between the two&lt;br /&gt;&lt;/pre&gt;今までは、内部データ構造はオブジェクト指向的な作り方にしていたわけですが、SmartDoxではcase classを使ってimmutableな構造をにしてみました。&lt;br /&gt;オブジェクト指向的な作りの場合、可変オブジェクトを複数のコンポーネントで共有して少しづつ変更を加えていくプログラミングモデルになりますが、代数的データ型(case class&amp;amp;immutable)にすると、コンポーネントで全複写しながら変換するプログラミングモデルになります。immutableにすると、なにか不測の事態があったときの回避方法が限られるためOOP派的には非常に怖い選択ですが、FPでは避けて通れない道です。&lt;br /&gt;SmartDoxでは、このプログラミングモデルにチャレンジしてみたわけです。今の所、特に問題もなく、このプログラミングモデルでもやっていけそうな感触を得ています。&lt;br /&gt;また、代数的データ構造を取っても、いざという時には型クラスの技法を使って色々細工ができそうという読みもありました。なにか問題が出てきたら試してみようと思っています。&lt;/div&gt;&lt;/div&gt;&lt;div class="outline-2" id="outline-container-6"&gt;&lt;h4 id="sec-6"&gt;Scalaz&lt;/h4&gt;&lt;div class="outline-text-2" id="text-6"&gt;&lt;a href="http://code.google.com/p/scalaz/"&gt;Scalaz&lt;/a&gt;は、型クラスと純粋関数型データ構造を提供するScalaライブラリです。Scalaの暗黙型変換、暗黙パラメータの機能を利用してHaskell的な型クラスを提供しています。&lt;br /&gt;Scalaプログラミングを足掛け4年程やってきて分かってきたのは、FPは関数の合成でプログラミングしていくのがコツということです。Scalaでも提供されているMonadという仕組みは、この関数合成のメカニズムの一種で普通の関数合成(composeやandThen, orElseなど)よりもより強力な関数合成を可能にします。このMonadを活用したプログラミングスタイルをMonadicプログラミングと呼ぶようです。&lt;br /&gt;Scalaの基本機能にもMonadはあるので、ScalaだけでもMonadicプログラミングはできるのですが、Scalazの強力な型クラス群を使用すると、さらに強力なMonadicプログラミングを行うことができるようになります。&lt;br /&gt;Scalazが用意している型クラスはたとえば、Monoid, Functor, Applicative Functor, Monadといったもので、MonadをKleisli圏で合成するようなこともできるようになっています。このあたりの型クラスを手足のように使えるようになるのが現在目標としていることで、そのためにSmartDoxではできるだけScalazを使ってプログラミングする方針にしています。&lt;br /&gt;Scalazを使うもう一つの効用は、Scalaで型クラスを使うためのよいお手本になるということ。Scalaでは、型クラスの機能は直接サポートされておらず、暗黙パラメタ、暗黙変換の機能を駆使して実装する必要があります。この実装技術をScalazで学ぶことができます。&lt;br /&gt;型クラスは、フレームワークと実装クラスを疎結合に保ちつつ(静的な)多態性を可能にする非常に強力な言語機能と理解しています。Scalazの技法を使えば、Scalaでも型クラスを使ったプログラミングが可能になるわけで、いずれ自分のプログラミング技法に取り入れたいと考えています。&lt;/div&gt;&lt;/div&gt;&lt;div class="outline-2" id="outline-container-7"&gt;&lt;h4 id="sec-7"&gt;パーサーコンビネータ&lt;/h4&gt;&lt;div class="outline-text-2" id="text-7"&gt;SmartDoxでは、SmartDox文書のパースにパーサーコンビネータを使ってみましたが、驚くほど簡単にパーサーを書くことができることが分かりました。&lt;br /&gt;パーサーの記述はBNF的なDSLになっていますが、基本的な動きとしてはMonadicでかつApplicativeという感じです。Parser[T]を返す関数がMonadic的な動き、その中で「^^」メソッドに渡すクロージャがApplicative的な動きと思います。&lt;br /&gt;簡単なパーサーであれば、BNF的DSLという理解の範囲で使えますが、細かいことをしようとするとMonadicかつApplicativeな動きを理解していないと辛そうです。パーサーコンビネータをある程度使いこなせるようになったのも、Scalazを使ってMonadicプログラミングに慣れてきた効用かなと思います。&lt;br /&gt;パーサーコンビネータを使っていて分かったのは、パーサーコンビネータは文字列以外にも使えるということ。DOMなどのXML木やマイ代数的データ型からパターンマッチングで構造を抽出してドメインモデルを構築するという用途には簡単に適用できそうです。翻って考えてみればこのあたりがMonadicプログラミングの威力ですね。&lt;br /&gt;&lt;br /&gt;&lt;hr /&gt;以上、SmartDoxを素材にScala+Scalazを中心としたFP技術を概観してきました。15年前はC→Javaによって、OOPがメインストリームのプログラミングパラダイムになりプログラミングの生産性が大きく向上しました。それと同等の大きなムーブメントがFPの本格導入により起こりそうです。もちろん前述したように、OOPは今後も軸の一つとなり続けるでしょうから、OOPとFPを融合した新しいプログラミングパラダイムという形になるでしょう。&lt;br /&gt;最後にどのプログラミング言語が残るのかは分かりませんが、現時点ではScala+Scalazで技を磨いておくのが有力な選択肢だと思います。&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7964484936470829118-6209869100336469509?l=modegramming.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://modegramming.blogspot.com/feeds/6209869100336469509/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://modegramming.blogspot.com/2012/01/smartdox_11.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/6209869100336469509'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/6209869100336469509'/><link rel='alternate' type='text/html' href='http://modegramming.blogspot.com/2012/01/smartdox_11.html' title='SmartDoxの実装技術'/><author><name>asami</name><uri>http://www.blogger.com/profile/12083671403528595185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_4HtJQwbXqEY/S4sSwhKz5fI/AAAAAAAAAFs/IvXW6ca5RGE/S220/profile.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7964484936470829118.post-7582878006863418387</id><published>2012-01-10T12:29:00.000+09:00</published><updated>2012-01-10T12:29:07.264+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='smartdox'/><title type='text'>SmartDox</title><content type='html'>&lt;p&gt;年末年始はまとまった時間が取れたこともあって、以前から構想していた文書処理アプリケーションの&lt;a href="https://github.com/asami/smartdoxprocessor"&gt;SmartDox&lt;/a&gt;を作ってみました。まだ、実用レベルではないですが一応ミニマムな実装が動いたところです。&lt;/p&gt;&lt;p&gt;SmartDoxは、1998年から作り続けているSmartDocの後継バージョンです。SmartDoc2という名前でもよかったのですが、smartdox.orgというドメイン名が取れたのでSmartDoxにしてみました。SmartDocの場合、ドメイン名にxmlsmartdoc.orgを使っているのですが、SmartDoxでは「XML」が必須でなくなるので「XML」の文言のないドメイン名を新しく使うことにしました。&lt;/p&gt;&lt;div id="outline-container-1" class="outline-2"&gt;&lt;h4 id="sec-1"&gt;動機&lt;/h4&gt;&lt;div class="outline-text-2" id="text-1"&gt;&lt;p&gt;1998年にSmartDocを作る時も、プレインテキストベース(当時だとsetext、今だとSphinxあたりが候補)にするかXMLベースにするかという選択があったのですが、プレインテキストベースだとパーサーを書くのが大変だったのと、当時のプレインテキストベースのマークアップ言語だと表組みや画像をマークアップする方法がなかったこともあって、XMLを選択しました。Emacsのsdoc-mode(sgml-modeを拡張)を使えば、XMLといっても入力、編集は問題ないので、SmartDocは現在まで使い続けています。&lt;/p&gt;&lt;p&gt;ではなぜSmartDocの新バージョンを作ることにしたのかというと以下の理由があります。&lt;/p&gt;&lt;ul&gt;&lt;li&gt;org-modeが構造化プレインテキストワープロであることが分かった&lt;/li&gt;&lt;li&gt;SimpleModelerで、モデルの仕様記述&lt;/li&gt;&lt;li&gt;自作アプリケーションで文章を扱うときの受け皿&lt;/li&gt;&lt;li&gt;Evernoteでの文書編集&lt;/li&gt;&lt;li&gt;iPad, iPhoneからの文書編集&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div id="outline-container-1-1" class="outline-3"&gt;&lt;h5 id="sec-1-1"&gt;org-mode&lt;/h5&gt;&lt;div class="outline-text-3" id="text-1-1"&gt;&lt;p&gt;org-modeは、Emacs上で動作するアウトラインプロセッサです。アウトラインプロセッサはMindmapModelingとの親和性も高そうなので、以前からOmni Outlinerやorg-modeを調べていたのですが、年末にorg-modeを触っていて、実は大変すごいことになっていることが判明しました。org-modeは、アウトラインプロセッシング機能を持った構造化プレインテキストワープロと呼んでも差し支えないEmacsアプリケーションだったのです。&lt;/p&gt;&lt;p&gt;特に驚愕したのは以下の機能。&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://d.hatena.ne.jp/tamura70/20100205/org"&gt;Emacs org-modeを使ってみる: (3) 表の編集&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://d.hatena.ne.jp/tamura70/20100222/org"&gt;Emacs org-modeを使ってみる: (19) graphvizとditaaの図を埋め込む&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Emacsをメインに使いながら今まで気づかなかったのは不覚でした。&lt;/p&gt;&lt;p&gt;org-modeの威力を目の当たりにし、今まで懸案にしていた色々なミッシングリンクが繋がってきました。そこで得たインスピレーションをベースにSmartDox開発を開始することにしたわけです。&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id="outline-container-1-2" class="outline-3"&gt;&lt;h5 id="sec-1-2"&gt;SimpleModelerで、モデルの仕様記述&lt;/h5&gt;&lt;div class="outline-text-3" id="text-1-2"&gt;&lt;p&gt;&lt;a href="http://code.google.com/p/simplemodeler/"&gt;SimpleModeler&lt;/a&gt;は、テキストDSLでモデルを記述し、このモデルからAppEngineやAndroidのアプリケーション(ドメインモデル+α)を生成するモデルコンパイラです。SimpleModelerでは、クラス図や状態遷移図/表を含んだ仕様書生成も行いますが、この仕様書で使用する自然言語による仕様記述の記述方法が懸案事項になっていました。SmartDocをベースにした記述方式を仮実装していたのですが、これをオーバーホールし、新規に本格的な文書処理系で実現するのがSmartDoxの目的の一つです。&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id="outline-container-1-3" class="outline-3"&gt;&lt;h5 id="sec-1-3"&gt;自作アプリケーションで文章を扱うときの受け皿&lt;/h5&gt;&lt;div class="outline-text-3" id="text-1-3"&gt;&lt;p&gt;SimpleModelerに限らず、自作アプリケーションで文章を扱いたいというニーズは色々あります。たとえば、ヘルプとして構造を持った長めの文章を表示したいとか、そういう細々した用途です。&lt;/p&gt;&lt;p&gt;この目的で、org-mode文書を操作するScalaコンポーネントを用意しておきたいというのが、SmartDoxの目的の一つです。ボクが開発するアプリケーションは&lt;a href="http://code.google.com/p/goldenport/"&gt;goldenport&lt;/a&gt;というアプリケーションフレームワーク上に構築していますが、&lt;a href="https://github.com/asami/smartdox"&gt;SmartDoxのコア&lt;/a&gt;はgoldenportからも切り離して、より汎用的な部品として使用できるようなアーキテクチャにしています。もちろんgoldenportでもSmartDoxに対応してSmartDoxをアプリケーションに容易に組み込む枠組みを提供する予定です。&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id="outline-container-1-4" class="outline-3"&gt;&lt;h5 id="sec-1-4"&gt;Evernoteでの文書編集&lt;/h5&gt;&lt;div class="outline-text-3" id="text-1-4"&gt;&lt;p&gt;ノートやアイデアの管理にEvernoteを使っていますが、Evernoteのエディタが今ひとつ使いづらいのと、Evernoteで記録した情報の再利用という目的で、Evernoteのエディタでも使用できる構造化プレインテキストの導入を考えていました。この目的にSmartDox文書を使用します。&lt;/p&gt;&lt;p&gt;また、Evernote APIを使ってSmartDox文書を格納したEvernoteノートの操作など、色々と面白い応用がありそうです。&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id="outline-container-1-5" class="outline-3"&gt;&lt;h5 id="sec-1-5"&gt;iPad, iPhoneからの文書編集&lt;/h5&gt;&lt;div class="outline-text-3" id="text-1-5"&gt;&lt;p&gt;最近はiPadやiPhoneからTextforceを用いてDropbox上のテキスト文書を編集する運用を行っています。&lt;/p&gt;&lt;p&gt;PCからはEmacsを使うのでXML系のテキスト文書でも問題はないのですが、Textforce(のようなプレインなテキストエディタ)でXML文書を編集するのはかなり辛いので、構造化プレインテキストの導入を考えていました。Evernoteの場合と同様に、ここもSmartDox文章がぴったりはまりそうです。&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id="outline-container-2" class="outline-2"&gt;&lt;h4 id="sec-2"&gt;コンセプト&lt;/h4&gt;&lt;div class="outline-text-2" id="text-2"&gt;&lt;p&gt;SmartDoxのコンセプトは、「(HTML5 + org-mode) / 2」です。(SmartDocのコンセプトは、「(HTML + LaTeX) / 2」で、これをXML上に構築していました。)&lt;/p&gt;&lt;p&gt;SmartDoxは、HTML5とorg-modeをごちゃまぜにした記述方式にしました。HTML5のサブセットとorg-modeのサブセットを合体させた文法にしています。(という予定です。現在はorg-mode上に一部HTML5を取り込んでいます。)&lt;/p&gt;&lt;p&gt;普通の範囲のHTML5文書をHTMLエディタで編集したテキスト、普通の範囲のorg-mode文書をEmacs上のorg-modeで編集したテキストの両方からHTML、プレインテキスト、LaTeX、PDFを生成します。(という予定です。)また、同一文章にHTML5とorg-modeを混在させ、さらにSmartDox専用の記述方式で技術文書向けの便利な指定も可能にします。&lt;/p&gt;&lt;p&gt;具体的には、以下のような記述になります。&lt;/p&gt;&lt;pre name="code" class="java"&gt;* SmartDox文書&lt;br /&gt;&lt;br /&gt;これは&amp;lt;b&amp;gt;SmartDox&amp;lt;/b&amp;gt;文書です。&lt;br /&gt;&lt;/pre&gt;&lt;pre name="code" class="java"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;&amp;lt;html&amp;gt;&lt;br /&gt;&amp;lt;head&amp;gt;&amp;lt;title&amp;gt;SmartDox文書&amp;lt;/title&amp;gt;&amp;lt;/head&amp;gt;&lt;br /&gt;&amp;lt;body&amp;gt;&lt;br /&gt;&amp;lt;section&amp;gt;&amp;lt;h2&amp;gt;SmartDox文書&amp;lt;/h2&amp;gt;&lt;br /&gt;&amp;lt;p&amp;gt;これは*SmartDox*文書です。&amp;lt;/p&amp;gt;&lt;br /&gt;&amp;lt;/section&amp;gt;&lt;br /&gt;&amp;lt;/body&amp;gt;&lt;br /&gt;&amp;lt;/html&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;org-modeを主体にして、細かい指定が必要なところはHTML5やSmartDox専用記述方式を併用するという運用イメージです。&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id="outline-container-3" class="outline-2"&gt;&lt;h4 id="sec-3"&gt;インストール&lt;/h4&gt;&lt;div class="outline-text-2" id="text-3"&gt;&lt;p&gt;プログラムの配布方法は、Scalaで最近注目されているconscriptにしました。conscriptのインストール方法は以下のページに詳しいです。&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://blog.twiwt.org/e/58baf0"&gt;conscript - Scala で作られたソフトウェアをインストールするためのツール&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Linux/Macであれば、以下のようにすればインストール完了です。&lt;/p&gt;&lt;pre class="console"&gt;$ curl https://raw.github.com/n8han/conscript/master/setup.sh | sh&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;conscriptをインストールした後、以下のようにしてSmartDoxをインストールします。&lt;/p&gt;&lt;pre class="console"&gt;$ cs asami/dox&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;以下の2つのコマンドがインストールされます。&lt;/p&gt;&lt;dl&gt;&lt;dt&gt;dox&lt;/dt&gt;&lt;dd&gt;SmartDoxコマンド&lt;/dd&gt;&lt;dt&gt;sdoc&lt;/dt&gt;&lt;dd&gt;SmartDocコマンド(互換用)&lt;/dd&gt;&lt;/dl&gt;&lt;/div&gt;&lt;div id="outline-container-3-1" class="outline-3"&gt;&lt;h5 id="sec-3-1"&gt;確認&lt;/h5&gt;&lt;div class="outline-text-3" id="text-3-1"&gt;&lt;p&gt;SmartDoxの文章として以下のものをsample.orgという名前で用意します。&lt;/p&gt;&lt;pre name="code" class="java"&gt;* 最初の章&lt;br /&gt;&lt;br /&gt;最初の章の文章。&lt;br /&gt;&lt;br /&gt;** 最初の節&lt;br /&gt;&lt;br /&gt;最初の節の文章。&lt;br /&gt;&lt;br /&gt;*** 最初の小節&lt;br /&gt;&lt;br /&gt;最初の小節の文章。&lt;br /&gt;&lt;br /&gt;| 名前 | 住所 |&lt;br /&gt;|------+------|&lt;br /&gt;| 太郎 | 横浜 |&lt;br /&gt;| 花子 | 東京 |&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;以下のようにSmartDoxのdoxコマンドを起動し、HTML5文書らしきものがsample.htmlで生成されればインストール成功です。(デバッグ用のスナップショットが出力されますが、ご愛嬌ということで)&lt;/p&gt;&lt;pre class="console"&gt;$ dox -html5 sample.org&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;SmartDoxは、まだPoC(Proof of Concept)の段階ですが、ボクが日々の作業の中で色々と作り足していく予定なので、いずれそれなりに機能が充実してくると思います。その時になったらぜひ試してみてください。&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7964484936470829118-7582878006863418387?l=modegramming.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://modegramming.blogspot.com/feeds/7582878006863418387/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://modegramming.blogspot.com/2012/01/smartdox.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/7582878006863418387'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/7582878006863418387'/><link rel='alternate' type='text/html' href='http://modegramming.blogspot.com/2012/01/smartdox.html' title='SmartDox'/><author><name>asami</name><uri>http://www.blogger.com/profile/12083671403528595185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_4HtJQwbXqEY/S4sSwhKz5fI/AAAAAAAAAFs/IvXW6ca5RGE/S220/profile.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7964484936470829118.post-1047955590660891546</id><published>2011-12-23T15:02:00.000+09:00</published><updated>2011-12-23T15:02:07.552+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java ee'/><category scheme='http://www.blogger.com/atom/ns#' term='scalaz'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>ScalazでBean Validation</title><content type='html'>&lt;p&gt;このエントリは&lt;a href="http://partake.in/events/33870915-f25b-40b6-9456-b898b898d48b"&gt;Scala Advent Calender 2011&lt;/a&gt;の第23日目です。&lt;br /&gt;&lt;p&gt;Java業界で今年最大のニュースといえば、&lt;a href="http://blogs.oracle.com/webcenter/entry/introducing_oracle_public_cloud_at"&gt;Oracle Open Worldで発表されたOracleのクラウド参入&lt;/a&gt;を上げる人も多いでしょう。OracleのPaaSが成功するのかどうかは未知数ですが、Java EEがPaaSのプラットフォームとして強力に推進されることは確実で、Java VM系での標準コンテナ仕様になるとみて間違いないと思います。&lt;br /&gt;&lt;p&gt;現状では、WebアプリケーションをJavaで作る場合TomcatやJettyなどの生ServletにSpringなどのフレームワークを載せて使うのが一般的で、Java EEのEJBはあまり使われていません。Java EEからEJBを引くと生Servletになるのであれば、Java EE仕様はあまり関係なくて、今まで通りTomcatやJettyベースでよいことになります。&lt;br /&gt;&lt;p&gt;しかし、実はJava EEのプラットフォームも地味に進歩してきていて、Java EEからEJB(のフルスペックやその他管理系の機能)を引いた部分の機能がかなり大きくなってきており、生Servletとの乖離が大きくなっています。この部分は、Java EEの&lt;a href="http://java.sun.com/developer/technicalArticles/JavaEE/JavaEE6Overview_Part3.html"&gt;Web Profile&lt;/a&gt;として仕様化もされています。Java EEのフルスペックは大変ですが、Web Profileなら使用頻度とのバランス的にリーズナブルな大きさであり、このWeb ProfileがJava VM系のPaaS標準仕様になると予想されるわけです。&lt;br /&gt;&lt;p&gt;ScalaもJava VM上で動作させることが普通なので、Javaプラットフォームの進化とは切っても切れない関係です。そういうわけでScalaでクラウドアプリケーションを書く場合も、Java EEのWeb Profileを念頭に置いておきたいところです。&lt;br /&gt;&lt;p&gt;Web Profileではいくつか重要な機能が追加されていますが、その一つが&lt;a href="http://docs.oracle.com/javaee/6/tutorial/doc/gircz.html"&gt;Bean Validation&lt;/a&gt;です。Bean Validationは、Java Beansのプロパティを検証する機能です。プロパティ(属性やメソッド)に対するアノテーションで指定された値の値域と実際に格納されている値がマッチしているか検証してくれます。この機能は、普通のJava SEベースのプログラムでも利用したいぐらいの便利な機能で、たまたまJava EEの枠組みで仕様化されていますが、事実上Javaの標準機能といえます。(Jarを追加すればJava SE上でも簡単に使えます。) そういう意味でもScalaプログラミングにも積極的に取り入れたいところです。&lt;br /&gt;&lt;p&gt;さて、ScalaでValidationといえばScalaz Validationですね(笑)。&lt;br /&gt;&lt;p&gt;Scalaz Validationは、applicative functorとして実現されたValidationクラスを中心とした機能で、いわゆるapplicative styleというプログラミングスタイルで、正常系処理と異常系処理を綺麗に取り扱うメカニズムを提供します。&lt;br /&gt;&lt;p&gt;Scalaでクラウドアプリケーションを作る場合、Beans ValidationとScalaz Validationを併用するのが望ましいことはいうまでもありません。そこで、この2つのValidationシステムを統一的に扱うためのプログラミング方法を試行することにしました。&lt;br /&gt;&lt;h4&gt;Person&lt;/h4&gt;&lt;p&gt;まず、検証対象となるクラスをPersonを定義します。通常のScalaクラスですが、属性に@NotNullや@Size(min=1)といったアノテーションがつけられている点がBean Validationのための追加点です。&lt;br /&gt;&lt;pre name="code" class="java"&gt;class Person(nm: String, ag: Int, ad: Option[String]) {&lt;br /&gt;  @NotNull @Size(min=1)&lt;br /&gt;  val name: String = nm&lt;br /&gt;  @Min(0) @Max(150)&lt;br /&gt;  val age: Int = ag;&lt;br /&gt;  @NotNull // Option内の判定はできない&lt;br /&gt;  val address: Option[String] = ad&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;本来は、case classを使いたいところですが、コンストラクタの引数につけたアノテーションをBean Validationは認識してくれないみたいなので、泣く泣くこの実装にしています。これは、ScalaからBean Validationを使うときの要注意項目ですね。&lt;br /&gt;&lt;p&gt;また、Optionの中身はBean Validationの基本機能では扱えないので、より本格的に作り込む場合は、カスタムのバリデーターを作る必要があります。&lt;br /&gt;&lt;h4&gt;Personのコンパニオンオブジェクト&lt;/h4&gt;&lt;p&gt;次に、Personクラスを操作するための関数を集めたコンパニオンオブジェクトPersonを定義します。ここで、Bean ValidationとScalaz Validationを接続する処理を実現します。&lt;br /&gt;&lt;p&gt;以下では、プログラムに直接コメントしていきます。&lt;br /&gt;&lt;pre name="code" class="java"&gt;object Person {&lt;br /&gt;  // Scalaでは、型名が長くなることが多いので、よく使うものはtypeで定義しておくとよい。&lt;br /&gt;  type ViolationNelA[A] = NonEmptyList[ConstraintViolation[A]]&lt;br /&gt;  type ViolationNel = ViolationNelA[Person]&lt;br /&gt;  type ValidationB[B] = Validation[ViolationNel, B]&lt;br /&gt;&lt;br /&gt;  // javax.validationパッケージからBeanValidationのValidatorを取得。&lt;br /&gt;  val validator = {&lt;br /&gt;    // Validationがscalaz.Validationと重なるので、BeanValidationという名前で取り込む。&lt;br /&gt;    import javax.validation.{Validation =&gt; BeanValidation}&lt;br /&gt;    val vf = BeanValidation.buildDefaultValidatorFactory()&lt;br /&gt;    vf.getValidator()&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  def isValid(p: Person) = validate(p).isEmpty&lt;br /&gt;&lt;br /&gt;  // Bean Validatorを使って、Personオブジェクトの検証を行う。&lt;br /&gt;  // asScala.toListでScalaのListに格納する。&lt;br /&gt;  // ConstraintViolationはBean Validatorが検出した異常情報。&lt;br /&gt;  def validate(p: Person): List[ConstraintViolation[Person]] = {&lt;br /&gt;    validator.validate(p).asScala.toList&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  // 指定された値からPersonオブジェクトを生成する。成功した場合はscalaz.SuccessにPersonオブジェクトを、失敗した場合はscalaz.FailureにConstraintViolationのリストを格納する。&lt;br /&gt;  // scalaz.Successとscalaz.FailureはScalaz.Validationのサブクラスでそれぞれ検証の成功と失敗を示す。&lt;br /&gt;  // この関数でBean Validationの結果をScalaz Validation化している。&lt;br /&gt;  def createV(name: String, age: Int, address: Option[String]): ValidationB[Person] = {&lt;br /&gt;    val p = new Person(name, age, address)&lt;br /&gt;    validate(p) match {&lt;br /&gt;      case vs if vs.isEmpty =&gt; p.success&lt;br /&gt;      // vs.toNel.get.failといったものがScalaz的な書き方。コンパクトに記述できる。&lt;br /&gt;      case vs =&gt; vs.toNel.get.fail&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  // Bean Validationは、Java Beanに値を設定した後にしか使えない。&lt;br /&gt;  // Webアプリなどで、生文字列からJava Beansを生成する場合、文字列が適切な値に変換できないため、そもそもJava Beansを生成できないケースもある。そのケースを取り扱うため、文字列からの値変換に失敗した場合はその時点でエラー、Java Beansを生成後はBean Validatorで検証し、いずれの場合も結果はscalaz.Validationで通知する。&lt;br /&gt;  def createVFromStrings(name: String, age: String, address: String): Validation[NonEmptyList[String], Person] = {&lt;br /&gt;    // 型名が長くなりがちなので、内部関数やvalで吸収する。&lt;br /&gt;    // 名前はコメントをつける気持ちでつけるとよい。&lt;br /&gt;    def parseint(s: String, name: String) = s.parseInt match {&lt;br /&gt;      case Success(a) =&gt; a.success[NonEmptyList[String]]&lt;br /&gt;      case Failure(e) =&gt; violationmsg(name, s, e.getMessage).fail.liftFailNel&lt;br /&gt;    }&lt;br /&gt;    def parsestring(a: String, name: String) = a.success[String].liftFailNel&lt;br /&gt;    def parseoption[T](a: Option[T], name: String) = a.success[String].liftFailNel&lt;br /&gt;    def constraintviolation2string(cv: ConstraintViolation[Person]) = {&lt;br /&gt;      violationmsg(cv.getPropertyPath.toString, cv.getInvalidValue.toString, cv.getMessage)&lt;br /&gt;    }&lt;br /&gt;    def violationmsg(path: String, value: String, msg: String) = {&lt;br /&gt;      "%s = %s: %s".format(path, value, msg)&lt;br /&gt;    }&lt;br /&gt;    // ロジックの中心は内部関数を使ってコンパクトに書く&lt;br /&gt;    (parsestring(name, "name") |@| parseint(age, "age") |@| parseoption(Option(address), "address"))(createV(_, _, _)) match {&lt;br /&gt;      case Success(Success(a)) =&gt; a.success[String].liftFailNel&lt;br /&gt;      case Success(Failure(e)) =&gt; e.map(constraintviolation2string(_)).fail&lt;br /&gt;      case Failure(e) =&gt; e.fail[Person]&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  // List[ValidationB[Person]]をValidationB[List[Person]]に変換。型クラスTraverseと似たような動き。&lt;br /&gt;  // TraverseでValidationをうまく扱うことができなかったので、foldrで実装してみた。&lt;br /&gt;  // 「(s &lt;**&gt; p)(_ :: _)」の所がapplicative styleのプログラミング。ValidationがSuccessの場合に走るロジック(正常処理)を記述する。ValidationがFailureの場合(異常処理)は、applicative functorであるValidationのコンテナ側が実装している裏ロジック(?)が走って、monoidとして実現されているエラー情報を蓄積していく。&lt;br /&gt;// applicative functorのメカニズムを用いることでプログラマが記述する正常系ロジックとValidationが自動的に実行する異常系ロジックを綺麗に分離できる。&lt;br /&gt;  def sequenceV(persons: List[ValidationB[Person]]): ValidationB[List[Person]] = {&lt;br /&gt;    persons.foldr(mzero[List[Person]].success[ViolationNel])((s, p) =&gt; (s &lt;**&gt; p)(_ :: _))&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;applicative functorはfunctorとmonadの中間に位置する型クラスです。それぞれ計算の文脈(コンテナ)の扱いに違いが出てきます。functorはピュアなアプリケーションロジック実行後ピュアな文脈(コンテナ)を生成、monadはアプリケーションロジックが文脈(コンテナ)を操作するのに対して、applicative functorはピュアなアプリケーションロジックの裏で暗黙的に文脈(コンテナ)が引き継がれていきます。このapplicative functorの有名な応用がValidationで、実際に触ってみるとピュアなアプリケーションロジックをベースに文脈(コンテナ)依存の処理を進められるapplicative styleのプログラミングがなかなか便利なことが分かります。&lt;br /&gt;&lt;h4&gt;ValidationMatchers&lt;/h4&gt;&lt;p&gt;Bean ValidationをScalaプログラムで扱うときは、ScalaTestのボキャブラリとなるカスタムマッチャーを作っておくと便利です。Bean ValidationとScalaz Validationを併用するので、両方の機能を包含したValidationMatchersを定義することにします。&lt;br /&gt;&lt;pre name="code" class="java"&gt;package advent2011&lt;br /&gt;&lt;br /&gt;import org.scalatest.matchers._&lt;br /&gt;import javax.validation.ConstraintViolation&lt;br /&gt;import scalaz._&lt;br /&gt;import Scalaz._&lt;br /&gt;&lt;br /&gt;// アプリケーションロジックのためのボキャブラリの追加はtraitの典型的な使い方の一つ。&lt;br /&gt;trait ValidationMatchers {&lt;br /&gt;  // Bean Validation用のボキャブラリ&lt;br /&gt;  def containViolations(violations: List[(String, String)]) = {&lt;br /&gt;    ContainViolationsMatcher(violations)&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  // Scalaz Validation用のボキャブラリ&lt;br /&gt;  object success extends ValidationSuccessMatcher&lt;br /&gt;  def fail(messages: List[String]) = {&lt;br /&gt;    ValidationFailMatcher(messages)&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// Bean Validation用のマッチャー。&lt;br /&gt;// BeMatcherやMatcherをextendsして、applyメソッドを定義するだけなので非常に簡単。&lt;br /&gt;// テスト用のボキャブラリを簡単に追加できる。&lt;br /&gt;case class ContainViolationsMatcher(violations: List[(String, String)]) extends BeMatcher[List[ConstraintViolation[_]]] {&lt;br /&gt;  def apply(value: List[ConstraintViolation[_]]) = {&lt;br /&gt;    def iscontain(nm: (String, String)) = {&lt;br /&gt;      val (name, message) = nm&lt;br /&gt;      value.any(v =&gt; v.getPropertyPath.toString == name &amp;&amp; v.getMessage == message)&lt;br /&gt;    }&lt;br /&gt;    // allはscalazの型クラスFoldableの関数。関数名に∀の記号を使うこともできる。&lt;br /&gt;    val result = violations.all(iscontain)&lt;br /&gt;    MatchResult(result, "does not contains expected violation", "contains expected violation")&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// Scalaz Validation用のマッチャー。Successの判定をする。&lt;br /&gt;case class ValidationSuccessMatcher() extends Matcher[Validation[NonEmptyList[String], _]] {&lt;br /&gt;  def apply(value: Validation[NonEmptyList[String], _]) = {&lt;br /&gt;    val result = value.isSuccess&lt;br /&gt;    MatchResult(result, "failure", "success")&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// Scalaz Validation用のマッチャー。Failureの判定をする。&lt;br /&gt;case class ValidationFailMatcher(messages: List[String]) extends Matcher[Validation[NonEmptyList[String], _]] {&lt;br /&gt;  def apply(value: Validation[NonEmptyList[String], _]) = {&lt;br /&gt;    value match {&lt;br /&gt;      case Success(a) =&gt; MatchResult(false, "incorrect success", "")&lt;br /&gt;      case Failure(e) =&gt; if (e.all(messages.contains)) {&lt;br /&gt;        MatchResult(true, "", "correct failure")&lt;br /&gt;      } else {&lt;br /&gt;        MatchResult(false, "incorrect failure", "")&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;h4&gt;PersonSpec&lt;/h4&gt;&lt;p&gt;最後に、Personの使い方をScalatestのWordSpecで書いてみました。WordSpecはBDD(Behavior Driven Development)スタイルのSpecを記述するためのクラスです。Scalatest標準のShouldMatchersに加えて、先ほど作成したValidationMatchersのボキャブラリを追加しています。&lt;br /&gt;ScalatestのBDDは、テスト用のアプリケーションロジックと結果判定がコーディングスタイル上明確に分離できるので、プログラムの視認性が高くなります。また、カスタムマッチャーを作り足すことで、より英文っぽい記述が可能になるので、そのあたりの遊び的な要素がプログラミングを進める上で良い感じです。&lt;br /&gt;&lt;pre name="code" class="java"&gt;class PersonSpec extends WordSpec with ShouldMatchers with ValidationMatchers {&lt;br /&gt;  "A Person" should {&lt;br /&gt;    "provide isValid and validate operation" that {&lt;br /&gt;      "against valid Person" in {&lt;br /&gt;        val p = new Person("taro", 30, "Yokohama".some)&lt;br /&gt;        Person.isValid(p) should be (true)&lt;br /&gt;        Person.validate(p) should be === Nil&lt;br /&gt;      }&lt;br /&gt;      "against invalid Person" in {&lt;br /&gt;        val p = new Person("", -150, null)&lt;br /&gt;        val expected = List("address" -&gt; "may not be null",&lt;br /&gt;                            "name" -&gt; "size must be between 1 and 2147483647",&lt;br /&gt;                            "age" -&gt; "must be greater than or equal to 0")&lt;br /&gt;        Person.isValid(p) should be (false)&lt;br /&gt;        Person.validate(p) should have length (expected.size)&lt;br /&gt;        // 追加したボキャブラリを使用&lt;br /&gt;        Person.validate(p) should be (containViolations(expected))&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;    "provide createV to create Person with Validation." that {&lt;br /&gt;      // アプリケーションロジックを普通のScalaプログラム的に書いた場合。&lt;br /&gt;      "Plain usage." in {&lt;br /&gt;        val taro = Person.createV("taro", 30, Some("Yokohama"))&lt;br /&gt;        val hanako = Person.createV("hanako", 25, Some("Kamakura"))&lt;br /&gt;        if (taro.isSuccess &amp;&amp; hanako.isSuccess) {&lt;br /&gt;          val tage = taro match {&lt;br /&gt;            case Success(p) =&gt; p.age&lt;br /&gt;          }&lt;br /&gt;          val hage = hanako match {&lt;br /&gt;            case Success(p) =&gt; p.age&lt;br /&gt;          }&lt;br /&gt;          val avg = (tage + hage) / 2.0&lt;br /&gt;          avg should be (27.5)&lt;br /&gt;        } else {&lt;br /&gt;          sys.error("invalid")&lt;br /&gt;        }&lt;br /&gt;      }&lt;br /&gt;      // アプリケーションロジックをScalazのapplicative styleで書いた場合。&lt;br /&gt;      // よりコンパクトで分かりやすく記述できる。&lt;br /&gt;      "Scalaz usage, applicative style." in {&lt;br /&gt;        val taro = Person.createV("taro", 30, Some("Yokohama"))&lt;br /&gt;        val hanako = Person.createV("hanako", 25, Some("Kamakura"))&lt;br /&gt;        val avgv = (taro &lt;**&gt; hanako)((x, y) =&gt; (x.age + y.age) / 2.0)&lt;br /&gt;        // この段階までValidationの文脈(コンテナ)の上で計算が進んでいる。&lt;br /&gt;        // 以下のmatch式で、アプリケーションロジックが正常に動作した場合と、エラーがある場合を分離して、それぞれのロジックを記述している。&lt;br /&gt;        avgv match {&lt;br /&gt;          case Success(avg) =&gt; avg should be (27.5)&lt;br /&gt;          case Failure(e) =&gt; sys.error("invalid")&lt;br /&gt;        }&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;    "provide createV and sequenceV for applicative style." that {&lt;br /&gt;     // ValidationのListを扱う場合2例。いずれもapplicative style。&lt;br /&gt;      "Use sequenceV to convert List[Validation[Person]] to Validation[List[Person]] " in {&lt;br /&gt;        val taro = Person.createV("taro", 30, Some("Yokohama"))&lt;br /&gt;        val hanako = Person.createV("hanako", 25, Some("Kamakura"))&lt;br /&gt;        val jiro = Person.createV("jiro", 35, Some("Tokyo"))&lt;br /&gt;        val persons = List(taro, hanako, jiro)&lt;br /&gt;        val personsv = Person.sequenceV(persons)&lt;br /&gt;        val avgv = personsv.map(x =&gt; x.map(_.age).sum.toFloat / x.length)&lt;br /&gt;        avgv match {&lt;br /&gt;          case Success(avg) =&gt; avg should be (30.0)&lt;br /&gt;          case Failure(errors) =&gt; sys.error("invalid")&lt;br /&gt;        }&lt;br /&gt;      }&lt;br /&gt;      "Use foldl to sum of age" in {&lt;br /&gt;        val taro = Person.createV("taro", 30, Some("Yokohama"))&lt;br /&gt;        val hanako = Person.createV("hanako", 25, Some("Kamakura"))&lt;br /&gt;        val jiro = Person.createV("jiro", 35, Some("Tokyo"))&lt;br /&gt;        val persons = List(taro, hanako, jiro)&lt;br /&gt;        val sumv = persons.foldl(0.success[Person.ViolationNel])((s, p) =&gt; (s &lt;**&gt; p)(_ + _.age))&lt;br /&gt;        val avgv = sumv.map(_.toFloat / persons.length)&lt;br /&gt;        avgv match {&lt;br /&gt;          case Success(avg) =&gt; avg should be (30.0)&lt;br /&gt;          case Failure(errors) =&gt; sys.error("invalid")&lt;br /&gt;        }&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;    "provide createVFromStrings to create Person from plain strings." that {&lt;br /&gt;      "Valid parameters." in {&lt;br /&gt;        val person = Person.createVFromStrings("taro", "30", "Yokohama")&lt;br /&gt;        // 追加したボキャブラリを使用&lt;br /&gt;        person should success&lt;br /&gt;      }&lt;br /&gt;      "Invalid parameters of type mismatch." in {&lt;br /&gt;        val person = Person.createVFromStrings("", "a", "Yokohama")&lt;br /&gt;        val expected = List("""age = a: For input string: "a"""")&lt;br /&gt;        // 追加したボキャブラリを使用&lt;br /&gt;        person should fail(expected)&lt;br /&gt;      }&lt;br /&gt;      "Invalid parameters of invalid value." in {&lt;br /&gt;        val person = Person.createVFromStrings("", "30", "Yokohama")&lt;br /&gt;        val expected = List("""name = : size must be between 1 and 2147483647""")&lt;br /&gt;        // 追加したボキャブラリを使用&lt;br /&gt;        person should fail(expected)&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;実行結果は以下のようになります。トップレベル, that,  inの三層でテストを整理できるのがなかなか便利です。&lt;br /&gt;&lt;pre class="console"&gt;[info] PersonSpec:&lt;br /&gt;[info] A Person &lt;br /&gt;[info]   should provide isValid and validate operation that &lt;br /&gt;[info]   - against valid Person&lt;br /&gt;[info]   - against invalid Person&lt;br /&gt;[info]   should provide createV to create Person with Validation. that &lt;br /&gt;[info]   - Plain usage.&lt;br /&gt;[info]   - Scalaz usage, applicative style.&lt;br /&gt;[info]   should provide createV and sequenceV for applicative style. that &lt;br /&gt;[info]   - Use sequenceV to convert List[Validation[Person]] to Validation[List[Person]] &lt;br /&gt;[info]   - Use foldl to sum of age&lt;br /&gt;[info]   should provide createVFromStrings to create Person from plain strings. that &lt;br /&gt;[info]   - Valid parameters.&lt;br /&gt;[info]   - Invalid parameters of type mismatch.&lt;br /&gt;[info]   - Invalid parameters of invalid value.&lt;br /&gt;[info] Passed: : Total 9, Failed 0, Errors 0, Passed 9, Skipped 0&lt;br /&gt;[success] Total time: 2 s, completed 2011/12/23 11:54:09&lt;/pre&gt;&lt;h4&gt;まとめ&lt;/h4&gt;&lt;p&gt;Bean ValidationとScalaz Validationを併用する方法について試行してみました。&lt;br /&gt;Bean Validation用のアノテーションとScalaの相性に若干問題があるようですが、プログラミング的には特に問題なくシームレスに繋げることが確認できました。&lt;br /&gt;&lt;p&gt;また、Scalaz Validationの実現技術であるapplicative functorによるapplicative styleによるプログラミング、ScalatestによるBDDという技術も合わせて使ってみました。いずれもJavaでは実用化が難しい技術で、Scalaを使うメリットですね。&lt;br /&gt;&lt;p&gt;今回使用した技術は以下のものになります。合わせてプログラミングしてみてJava EE web profile技術、Scalaz、ScalaTestによるTDD/BDDといったところがScalaプログラミングのベースになりそう、という感を強くしました。&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Bean Validation&lt;br /&gt;&lt;li&gt;Scalaz Validation&lt;br /&gt;&lt;li&gt;Scalaz applicative functor (applicative style)&lt;br /&gt;&lt;li&gt;Scalatest BDD&lt;br /&gt;&lt;li&gt;Scalatest カスタムマッチャー&lt;br /&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7964484936470829118-1047955590660891546?l=modegramming.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://modegramming.blogspot.com/feeds/1047955590660891546/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://modegramming.blogspot.com/2011/12/scalazbean-validation.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/1047955590660891546'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/1047955590660891546'/><link rel='alternate' type='text/html' href='http://modegramming.blogspot.com/2011/12/scalazbean-validation.html' title='ScalazでBean Validation'/><author><name>asami</name><uri>http://www.blogger.com/profile/12083671403528595185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_4HtJQwbXqEY/S4sSwhKz5fI/AAAAAAAAAFs/IvXW6ca5RGE/S220/profile.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7964484936470829118.post-1131012252304536881</id><published>2011-12-14T19:00:00.000+09:00</published><updated>2011-12-14T19:00:30.572+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='simplemodeler'/><category scheme='http://www.blogger.com/atom/ns#' term='java'/><title type='text'>ImmutableとBuilder</title><content type='html'>&lt;p&gt;このエントリは&lt;a href="http://atnd.org/events/22434"&gt;Java Advent Calender 2011&lt;/a&gt;の第14日目です。&lt;br /&gt;&lt;p&gt;OOPで最も重要なテクニックは何でしょうか。色々な考え方があるでしょうが、ボクはImmutable Objectがまず最初に浮かびます。&lt;br /&gt;かなり前にJava World誌に書いていたJavaデザインノートという連載でも、第1回のテーマはImmutable Objectでした。&lt;br /&gt;&lt;p&gt;Immutable Object(不変オブジェクト)は、生成時に属性を設定した後、属性値を変更することができないオブジェクトです。Javaの場合、StringやDateなどの情報を保持する基本クラスの多くがImmutable Objectになっており、Javaプログラミングを下支えしています。&lt;br /&gt;&lt;p&gt;Immutable Objectの長所は、とにかく属性値が変更されないこと。一度生成したオブジェクトは何の心配もなく、メソッドの引数で渡すことができます。その先で、どのような共有のされかたをしても、知らないところで勝手に内容が変更されるということがありません。マルチスレッドプログラミングでは、この性質はさらに重要になります。&lt;br /&gt;&lt;p&gt;一方、Immutable Objectは以下の短所があります。&lt;br /&gt;&lt;ol&gt;&lt;li&gt;値を変更するためには、オブジェクトをまるごと複写する必要がある。&lt;br /&gt;&lt;li&gt;すべての値の設定をオブジェクト生成時に行う必要があり、プログラミングがちょっと煩雑。&lt;br /&gt;&lt;/ol&gt;&lt;p&gt;前者の問題は、最近のハードウェア性能の向上で、普通のWebアプリ、業務アプリではまず問題にはならないでしょう。まるごと複写といってもshallow copyとなるので、まるまるデッドコピーとはなるわけではありません。 また、多少の性能劣化があっても、プログラム品質、開発効率の向上の方がより重要というケースは多いはずです。 よほど性能要件の高い場合でも適材適所で使い分ければよいわけです。 &lt;p&gt;そういう意味で、Value Objectは当然として、DTOといった情報量の多いオブジェクトもできるだけImmutable Object化していきたいところです。 &lt;p&gt;となると、現在問題となるのは後者。まずオブジェクト生成時のコンストラクタで全情報を引数で渡さなければなりません。さらに、オブジェクトの変更(つまりデータを変更して複写)では、オブジェクトのほとんどの情報と変更したいデータを用意して、コンストラクタに渡すという手間が必要になります。 StringやDateのようなValue Objectでは、オブジェクトが管理する情報が1つやせいぜい2つなので全く問題ありませんが、DTO等の場合は管理する情報が数十個になるケースも考えられ、かなり煩雑になります。数十個と言わずとも5個ぐらいでも十分嫌になります。実際のプログラミングではこの手間が嫌で、Immutableの方がよいと分かっていても普通のMutable Objectを選択することになりがちです。これを何とかしたいですね。 &lt;p&gt;この問題を解決するのがBuilderです。 &lt;p&gt;プログラムはこんな感じ。 &lt;p&gt;Immutable Object「Person」と、そのBuilderである「Person.Builder」を定義しています。Personは、Immutable Objectであることを活用して属性をpublicにして外から扱いやすくしています。Person.Builderの方は、普通のMutableオブジェクトで、値を設定しやすくするための工夫を好きなだけ行うことができます。ここではwithXXXメソッドでメソッドチェインを実現してみました。&lt;pre name="code" class="java"&gt;package advent2011;&lt;br /&gt;&lt;br /&gt;import java.util.List;&lt;br /&gt;import java.util.ArrayList;&lt;br /&gt;import static java.util.Collections.unmodifiableList;&lt;br /&gt;&lt;br /&gt;public class Person {&lt;br /&gt;    public final String name;&lt;br /&gt;    public final int age;&lt;br /&gt;    public final String address;&lt;br /&gt;    public final List&amp;lt;String&gt; phones;&lt;br /&gt;&lt;br /&gt;    public Person(String name, int age, String address,&lt;br /&gt;                  List&amp;lt;String&gt; phones) {&lt;br /&gt;        this.name = name;&lt;br /&gt;        this.age = age;&lt;br /&gt;        this.address = address;&lt;br /&gt;        this.phones = unmodifiableList(new ArrayList&amp;lt;String&gt;(phones));&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public static class Builder {&lt;br /&gt;        public String name;&lt;br /&gt;        public int age;&lt;br /&gt;        public String address;&lt;br /&gt;        public ArrayList&amp;lt;String&gt; phones = new ArrayList&amp;lt;String&gt;();&lt;br /&gt;&lt;br /&gt;        public Builder() {&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public Person build() {&lt;br /&gt;            return new Person(name, age, address, phones);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public Builder withName(String name) {&lt;br /&gt;            this.name = name;&lt;br /&gt;            return this;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public Builder withAge(int age) {&lt;br /&gt;            this.age = age;&lt;br /&gt;            return this;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public Builder withAddress(String address) {&lt;br /&gt;            this.address = address;&lt;br /&gt;            return this;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public Builder withPhone(String phone) {&lt;br /&gt;            this.phones.add(phone);&lt;br /&gt;            return this;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;こんな感じで使います。 &lt;pre name="code" class="java"&gt;package advent2011;&lt;br /&gt;&lt;br /&gt;import org.junit.Test;&lt;br /&gt;import static org.hamcrest.core.Is.is;&lt;br /&gt;import static org.junit.Assert.*;&lt;br /&gt;&lt;br /&gt;public class PersonTest {&lt;br /&gt;    @Test&lt;br /&gt;    public void buildPerson() {&lt;br /&gt;        Person.Builder builder = new Person.Builder();&lt;br /&gt;        builder.withName("Taro")&lt;br /&gt;            .withAge(30)&lt;br /&gt;            .withAddress("Yokohama")&lt;br /&gt;            .withPhone("045-123-4567");&lt;br /&gt;        Person person = builder.build();&lt;br /&gt;        assertThat(person.name, is("Taro"));&lt;br /&gt;        assertThat(person.age, is(30));&lt;br /&gt;        assertThat(person.address, is("Yokohama"));&lt;br /&gt;        assertThat(person.phones.get(0), is("045-123-4567"));&lt;br /&gt;        System.out.println(person);&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Personオブジェクトを生成す時の手間は、普通のMutableオブジェクトの時と同じ。 buildメソッドで返ってくるPersonオブジェクトはImmutableオブジェクトなので、安全に使うことができます。 どちらの目的も叶える解ですね！ &lt;h4&gt;新たな問題&lt;/h4&gt;&lt;p&gt;さて、Builderを使うとImmutableオブジェクトが使いやすくなるのは分かったのですが、新たに別の問題が発生します。 &lt;p&gt;このBuilderを用意する手間がなかなか大変なんです。コーディング量も多いですし、コーディング内容が単純作業のためが短調で面白くない、という問題もあります。 この手間があるので、このままでは結局使わないテクニックになってしまいそうです。&lt;p&gt;単調なコーディングあるところ、自動生成あり。ここで登場するのが自動生成です。クラスの形が分かっていれば、その情報からJavaプログラムのソースコードを生成すればよることが可能です。 &lt;h4&gt;SimpleModelerService&lt;/h4&gt;現在開発中のSimpleModelerServiceでは、この問題に対応するためにDSLからJavaプログラムを自動生成する機能を提供する予定です。DSLにはScala DSLに加えて、CSV、マインドマップ(XMind)、Excelなどが利用できるようになる予定です。今回は、CSVを使って試してみましょう。&lt;p&gt;以下の内容のCSVファイルを用意します。 &lt;pre name="code" class="java"&gt;person,name;age(int);address?;phone+&lt;/pre&gt;&lt;p&gt;CSVの第1カラムにクラス名、第2カラムに属性のリストを定義しています。「(int)」はint型、「?」「+」は多重度(?は0または1、+は1以上)を意味しています。&lt;p&gt;これを以下のフォームに設定して「生成」すると、色々なコードが生成されたものをzipで固めたものが返ってきます。 &lt;p&gt;この中にある、&lt;tt&gt;DDPerson.java&lt;/tt&gt;に今回のテーマであるImmutableオブジェクトとBuilderが記述されています。ぜひ覗いてみてください。 &lt;div style="padding: 10px"&gt;&lt;div style="border: solid 2px black;border-radius: 10px;padding: 10px"&gt;&lt;form xmlns="http://www.w3.org/1999/xhtml" action="http://service.simplemodeling.org/simplemodeler/java" enctype="multipart/form-data" method="POST"&gt;&lt;input name="source.package" type="hidden" value="advent2011"/&gt; ファイル名: &lt;input name="_1" type="file" /&gt; &lt;input type="submit" value="生成" /&gt;&lt;/form&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;ImmutableオブジェクトとそのBuilderの作成は、手間がかかるのでつい手抜きをしたくなりますが、プログラムの自動生成を活用すれば楽々クリアできますね。&lt;br /&gt;SimpleModelerのJava生成機能は、近々公開したいと思いますので、ぜひご利用ください。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7964484936470829118-1131012252304536881?l=modegramming.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://modegramming.blogspot.com/feeds/1131012252304536881/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://modegramming.blogspot.com/2011/12/immutablebuilder.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/1131012252304536881'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/1131012252304536881'/><link rel='alternate' type='text/html' href='http://modegramming.blogspot.com/2011/12/immutablebuilder.html' title='ImmutableとBuilder'/><author><name>asami</name><uri>http://www.blogger.com/profile/12083671403528595185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_4HtJQwbXqEY/S4sSwhKz5fI/AAAAAAAAAFs/IvXW6ca5RGE/S220/profile.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7964484936470829118.post-7201128364028526574</id><published>2011-12-07T09:13:00.000+09:00</published><updated>2011-12-07T09:13:05.653+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='simplemodeler'/><category scheme='http://www.blogger.com/atom/ns#' term='g3'/><category scheme='http://www.blogger.com/atom/ns#' term='goldenport'/><title type='text'>SimpleModelerServiceのアーキテクチャ</title><content type='html'>&lt;p&gt;昨日公開したXMind→クラス図変換サービスは、g3上に構築したSimpleModelerServiceというRESTサービスです。&lt;br /&gt;このRESTサービスはScalaでプログラミングし、WAR形式にパッケージングしたものをGlassFish上で動作させています。&lt;br /&gt;Java系のPaaS標準コンテナは、WAR形式をJavaEEのWebプロファイル＋αを動作させるものになると予想されるので、この環境をScala＆自作フレームワークで試してみるというという目的もありました。&lt;br /&gt;&lt;p&gt;SimpleModelerServiceは以下の4つのモジュールから構成されています。&lt;br /&gt;&lt;dl&gt;&lt;dt&gt;&lt;a href="http://code.google.com/p/goldenport/"&gt;Goldenport&lt;/a&gt;&lt;br /&gt;&lt;dd&gt;アプリケーションフレームワーク&lt;br /&gt;&lt;dt&gt;&lt;a href="http://code.google.com/p/goldenport3/"&gt;g3&lt;/a&gt;&lt;br /&gt;&lt;dd&gt;クラウドアプリケーションフレームワーク&lt;br /&gt;&lt;dt&gt;&lt;a href="http://code.google.com/p/simplemodeler/"&gt;SimpleModeler&lt;/a&gt;&lt;br /&gt;&lt;dd&gt;モデルコンパイラ&lt;br /&gt;&lt;dt&gt;SimpleModelerService&lt;br /&gt;&lt;dd&gt;SimpleModelerサービス&lt;br /&gt;&lt;/dl&gt;&lt;p&gt;SimpleModelerServiceが最上位にあるクラウドアプリケーションの本体で、g3上に構築されています。SimpleModelerServiceはgoldenport上に構築されたスタンドアロンアプリケーションであるSimpleModelerをRESTサービス化します。&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-egoNbN2XNmE/Tt5wekBo0PI/AAAAAAAAAQI/2x380aCBpT8/s1600/SimpleModelerServiceArch.png" imageanchor="1"&gt;&lt;img border="0" height="152" src="http://3.bp.blogspot.com/-egoNbN2XNmE/Tt5wekBo0PI/AAAAAAAAAQI/2x380aCBpT8/s400/SimpleModelerServiceArch.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;p&gt;SimpleModelerServiceの開発規模は以下の表になります。Scalaが約121.6Ks、Javaが約10.8Ksです。Scalaのコーディング量が100Kステップを超えてきておりちょっと感慨深いものがあります。&lt;br /&gt;&lt;table class="data"&gt;&lt;caption&gt;開発規模&lt;/caption&gt;&lt;thead&gt;&lt;tr&gt;&lt;th align="center"&gt;モジュール&lt;/th&gt;&lt;th align="center"&gt;Scala(Ks)&lt;/th align="center"&gt;&lt;th&gt;Java(Ks)&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt; &lt;tbody&gt;&lt;tr&gt; &lt;td&gt;Goldenport&lt;/td&gt;&lt;td align="right"&gt;16.8&lt;/td&gt;&lt;td align="right"&gt;9.1&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;g3&lt;/td&gt;&lt;td align="right"&gt;22.6&lt;/td&gt;&lt;td align="right"&gt;1.7&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;SimpleModeler&lt;/td&gt;&lt;td align="right"&gt;82.1&lt;/td&gt;&lt;td align="center"&gt;N/A&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;SimpleModelerService&lt;/td&gt;&lt;td align="right"&gt;0.1&lt;/td&gt;&lt;td align="center"&gt;N/A&lt;/td&gt; &lt;/tr&gt;&lt;/tbody&gt; &lt;/table&gt;&lt;h4&gt;SimpleModelerService on g3&lt;/h4&gt;&lt;p&gt;SimpleModelerServiceでは、クラウドアプリケーション用フレームワークとして開発してきたg3を実応用に初めて適用することができました。&lt;br /&gt;&lt;p&gt;g3はScala DSLでアプリケーションを記述しますが、SimpleModelerServiceは以下のものになります。&lt;br /&gt;&lt;pre class="java" name="code"&gt;class SimpleModelerService extends G3Application {&lt;br /&gt;  title = "SimpleModeler"&lt;br /&gt;  summary = &lt;div&gt;SimpleModeler service produces various artifacts from a SimpleModeling model.&lt;/div&gt;port("/diagram",&lt;br /&gt;      Description(&lt;br /&gt;          "Diagram", "SimpleModeler Diagram Service",&lt;br /&gt;          &lt;div locale="en"&gt;SimpleModeler diagram service produces a class diagram from a mindmap modeled by MindmapModeling.&lt;/div&gt;,&lt;br /&gt;          Schema(&lt;br /&gt;              (Symbol("source.package"), XString, MZeroOne),&lt;br /&gt;              ('_1, XBase64Binary)))&lt;br /&gt;  ) agentpf {&lt;br /&gt;    case p: Post =&amp;gt; Post("diagram", p)&lt;br /&gt;  } invoke('sm)&lt;br /&gt;&lt;br /&gt;  goldenport('sm, SimpleModelerDescriptor)&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;port("/diagram")はHTTPリクエストを受け取るポートを指定しています。&lt;br /&gt;URIの断片"/diagram"にマッチしたHTTPリクエストがこのポートで受信され、パイプラインで以下の処理が実行されていきます。&lt;br /&gt;&lt;ol&gt;  &lt;li&gt;agentpfでPostリクエストを加工するPartialFunctionを実行。&lt;br /&gt;  &lt;li&gt;invokeでチャネルsmを呼出し。&lt;br /&gt;&lt;/ol&gt;&lt;p&gt;その下にある&lt;code&gt;goldenport('sm, SimpleModelerDescriptor)&lt;/code&gt;は、チャネルsmをGoldenportアプリケーションSimpleModelerに割り当てる設定です。SimpleModelerのGoldenport DSLであるSimpleModelerDescriptorを指定しています。&lt;p&gt;&lt;code&gt;port("/diagram")&lt;/code&gt;からinvokeでこのsmチャネル経由でSimpleModelerが実行され、その実行結果が&lt;code&gt;port("/diagram")&lt;/code&gt;の実行結果としてクライアントに返されます。&lt;p&gt;HTTPのプロトコル処理、FormやJSON、AtomPub, MIMEといったデータ入出力、ファイルのアップロード処理はg3フレームワークが行います。アプリケーションは、GetやPostといったメッセージに対する関数型的な転換処理の連鎖として、アプリケーションロジックを記述することができます。また、Goldenport上に構築したスタンドアロンアプリケーションは、シームレスに接続できるようになっており、ほぼそのままRESTサービス化することができます。&lt;h4&gt;SimpleModeler on Goldenport&lt;/h4&gt;&lt;p&gt;モデルコンパイラはアプリケーションフレームワークGoldenport上に構築しています。そのアーキテクチャを定義するDSLが以下のSimpleModelerDescriptorです。&lt;pre class="java" name="code"&gt;class SimpleModelerDescriptor extends GApplicationDescriptor {&lt;br /&gt;  name = "SimpleModeler"&lt;br /&gt;  version = "0.3.0"&lt;br /&gt;  version_build = "20111206"&lt;br /&gt;  copyright_years = "2008-2011"&lt;br /&gt;  copyright_owner = "ASAMI, Tomoharu"&lt;br /&gt;  command_name = "sm"&lt;br /&gt;  //&lt;br /&gt;  classpath("target/classes")&lt;br /&gt;  importers(ScalaDslImporter)&lt;br /&gt;  entities(CsvEntity, XMindEntity, OpmlEntity, ExcelTableEntity, &lt;br /&gt;      OrgmodeEntity, YamlEntity)&lt;br /&gt;  services(ProjectRealmGeneratorService,&lt;br /&gt;    ImportService,&lt;br /&gt;    ConvertService,&lt;br /&gt;    HtmlRealmGeneratorService,&lt;br /&gt;//    JavaRealmGeneratorService,&lt;br /&gt;    GrailsRealmGeneratorService,&lt;br /&gt;    GaeRealmGeneratorService,&lt;br /&gt;    GaeoRealmGeneratorService,&lt;br /&gt;    GaeJavaRealmGeneratorService,&lt;br /&gt;    AndroidGeneratorService,&lt;br /&gt;    G3GeneratorService,&lt;br /&gt;    AsakusaGeneratorService,&lt;br /&gt;    DiagramGeneratorService)&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;SimpleModelerDescriptorでは概ね以下のような定義を行っています。&lt;ul&gt;&lt;li&gt;importersで外部データの移入器としてScalaDslImporterを指定。&lt;br /&gt;&lt;li&gt;entitiesでCsvEntityやXMindEntityなどを指定。サフィックスがcsvやxmlになっているファイルを入力すると、自動的にCSVEntityやXMindEntityに変換される。&lt;br /&gt;&lt;li&gt;servicesでDiagramGeneratorServiceやAndroidGeneratorServiceなどを指定。パラメタにより自動的に適合するサービスが起動される。&lt;br /&gt;&lt;/ul&gt;&lt;p&gt;Goldenportが外部入出力のもろもろをハンドリングしてくれるので、アプリケーションロジックの記述に専念することができます。g3を併用することでRESTサービスまでシームレスに接続できるようになりました。&lt;h4&gt;ScalaとDSL&lt;/h4&gt;&lt;p&gt;DSLの用途は大きく(1)モデルなどの静的な情報を記述、(2)フレームワークのAPIを記述、の2つに分けられます。&lt;p&gt;SimpleModelerがモデル記述に使っているScala DSLは前者の例です。&lt;p&gt;一方、本記事で取り上げたSimpleModelerService(g3)、SimpleModeler(Goldenport)は後者の例です。SimplModeler(Goldenport)のDSLは、Javaでも何とか実現できそうですが、SimpleModelerServiceのDSLはJavaではこのような記述は難しく、DSLを得意とするScalaの美点がよく出ています。&lt;p&gt;Scalaは元々、JavaでのDSL実現に限界を感じていたため、DSL用の言語として採用したのですが、十分満足できる結果を得られました。Scalaで100K超のコーディングを行った事になりますが、Javaと比べてプログラミングが圧倒的に楽ということも体感できました。&lt;p&gt;Goldenportやg3のようなDSLベースのAPIを持つフレームワークやコンポーネントがこれからどんどん出てくることが予想されるので、Scalaプログラミングの生産性はますます向上してくることになるでしょう。また、メニーコア時代の並行プログラミングは関数型言語を中心に広がっていきそうです。今回確認できたようにGlassFishのようなJava用のクラウドコンテナ(の候補)にもまったくシームレスに載せることができるのは、Javaとの互換性を軸に据えているScalaならではです。色々考えていくとScalaはかなり便利な言語で、クラウドアプリケーション向けプログラミング言語の最右翼かなと実感しています。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7964484936470829118-7201128364028526574?l=modegramming.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://modegramming.blogspot.com/feeds/7201128364028526574/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://modegramming.blogspot.com/2011/12/simplemodelerservice.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/7201128364028526574'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/7201128364028526574'/><link rel='alternate' type='text/html' href='http://modegramming.blogspot.com/2011/12/simplemodelerservice.html' title='SimpleModelerServiceのアーキテクチャ'/><author><name>asami</name><uri>http://www.blogger.com/profile/12083671403528595185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_4HtJQwbXqEY/S4sSwhKz5fI/AAAAAAAAAFs/IvXW6ca5RGE/S220/profile.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-egoNbN2XNmE/Tt5wekBo0PI/AAAAAAAAAQI/2x380aCBpT8/s72-c/SimpleModelerServiceArch.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7964484936470829118.post-4553393735141900274</id><published>2011-12-06T11:17:00.001+09:00</published><updated>2011-12-06T11:19:35.182+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='simplemodeler'/><category scheme='http://www.blogger.com/atom/ns#' term='mindmapmodeling'/><title type='text'>XMindをクラス図に変換するクラウドサービス</title><content type='html'>XMind形式のマインドマップモデルからクラス図(PNG)を生成するクラウドサービスを作成しました。&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.mindmapmodeling.org/service"&gt;http://www.mindmapmodeling.org/service&lt;/a&gt;&lt;br /&gt;&lt;/ul&gt;次回の横浜モデリング勉強会(1月21日(土)予定)で使用する予定です。作成中のマインドマップをクラス図に変換して確認することによって、マインドマップモデルとオブジェクトモデルの関係をより深く理解できるようになると思います。  &lt;p&gt;ツールをインストールするのは何かと大変なので、開発中のツールはこういったクラウドサービスで提供していく予定です。  &lt;p&gt;このツールは、CURLコマンドまたはWeb上に置いたガジェット(HTML断片)を使って使用することができます。  &lt;p&gt;Bloggerで、このガジェットが動くのか試すために以下で配置してみました。もしかしたらここから動かすことができるかもしれません。  &lt;div style="padding: 10px"&gt;&lt;div style="border: solid 2px black;border-radius: 10px;padding: 10px"&gt;&lt;form xmlns="http://www.w3.org/1999/xhtml" action="http://service.simplemodeling.org/simplemodeler/diagram" enctype="multipart/form-data" method="POST"&gt;&lt;input name="source.package" type="hidden" value="model"/&gt; ファイル名: &lt;input name="_1" type="file" /&gt; &lt;input type="submit" value="生成" /&gt;&lt;/form&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;クラウドサービスの配備には、さくらインターネットとGlassFishを使ってみました。&lt;br /&gt;この組合せは、かなり簡単にScalaアプリケーションが動きますね。&lt;br /&gt;どちらのUIもこなれていて作業のハードルが低いので、気軽に色々試してみたいと思います。&lt;br /&gt;&lt;br /&gt;追記：Bloggerからもガジェット動きました。サービスはまだまだ柔らかいので、変なことをすると落ちるかもしれません。お手柔らかに。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7964484936470829118-4553393735141900274?l=modegramming.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://modegramming.blogspot.com/feeds/4553393735141900274/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://modegramming.blogspot.com/2011/12/xmind.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/4553393735141900274'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/4553393735141900274'/><link rel='alternate' type='text/html' href='http://modegramming.blogspot.com/2011/12/xmind.html' title='XMindをクラス図に変換するクラウドサービス'/><author><name>asami</name><uri>http://www.blogger.com/profile/12083671403528595185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_4HtJQwbXqEY/S4sSwhKz5fI/AAAAAAAAAFs/IvXW6ca5RGE/S220/profile.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7964484936470829118.post-5506803217038263550</id><published>2011-12-02T16:08:00.000+09:00</published><updated>2011-12-02T16:08:26.821+09:00</updated><title type='text'>要約エンティティ</title><content type='html'>きのう「Deep Hadoop Night～誰がHadoopを殺したか？～」を聞いてきました。タイトルからも分かるように刺激的な内容でしたがオフレコが趣旨とのことで内容への感想は差し控えますが、それはともかく、座談会のお話に色々なヒントが満載で、クラウドアプリケーションのモデリングを考える上でとても刺激になりました。&lt;br&gt;&lt;br /&gt;Hadoop的なサービスが普通のインフラとして整備された世界での、クラウドアプリケーションのモデリング手法について考察が進みました。今まで考えていたアイデアが少しまとまってきたので、つらつら、まとめておきたいと思います。&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;&lt;a name="doc1_id8"&gt;データモデル&lt;/a&gt;&lt;br /&gt;&lt;/h4&gt;以下の図は、ここ数年、クラウドアプリケーションのメタモデルの素案として使用しているものを今回のアイデアに基づき改良したものです。&lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-TnkJaLrMqvY/Tth2pThNOyI/AAAAAAAAAPk/OVjAVUVpmrw/s1600/modelMap.png" imageanchor="1" style=""&gt;&lt;img border="0" height="199" width="400" src="http://1.bp.blogspot.com/-TnkJaLrMqvY/Tth2pThNOyI/AAAAAAAAAPk/OVjAVUVpmrw/s400/modelMap.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;基本的にはクラウド以前に使っていたメタモデルを自然に拡張したものになっています。概念モデルや分析モデルのあたりは、要するに利用者などのステークホルダー観点でのモデルを構築することになるので、クラウドプラットフォームだからといって、特別な手法を取り込むということにはならないと考えています。&lt;br&gt;&lt;br /&gt;もちろん、クラウドによって今まであったシステム構築上の制約が外れてくるので、そのあたりで新たに考慮に入れる必要がある要因は増えてきます。&lt;br&gt;&lt;br /&gt;このメタモデルは、2008年頃からクラウド向けに徐々に改良してきたもので、クラウド向けのモデル要素として以下のものを追加してきました。&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt; アプリケーション利用モデルのUX(User Experience)&lt;br /&gt;&lt;li&gt; アプリケーション実現モデルのメッセージフロー&lt;/ul&gt;UX(User Experience)は、UCD(User Centered Design)によるUIモデリング技術の発展とGUI技術の向上を取り込む意図です。UXをシステムに落し込む時の技術としてユースケースを組み合わせることを考えています。ユースケースのカバー範囲が少し小さくなるとともに、ユースケースをシステム設計側のモデリング技術として再構築することを想定しています。&lt;br&gt;メッセージフローは、さまざまなシステム間でのメッセージ交換によって協調動作するクラウドアプリケーションのアーキテクチャを、制御フローとデータフローを統合した形で記述する目的のものです。ただし、システム設計レベルの詳細な記述力は持たないので、プログラムの自動生成といった用途には使用できません。&lt;br&gt;ここまでは、以前からあちこちでお話ししている内容なのですが、これに加えて、今回新たなモデル要素として「要約エンティティ」を追加することにしました。この「要約エンティティ」がクラウドアプリケーションのモデリングの要になるのでは、と思いついたわけです。&lt;h4&gt;&lt;a name="doc1_id22"&gt;ドメインモデル&lt;/a&gt;&lt;/h4&gt;分析モデル、設計モデルの軸となるのがドメインモデルです。(以下、正確には振舞いを含んだオブジェクトモデルですが、イメージしづらいのでデータモデルとして考えていきます。)&lt;br&gt;ポイントとなるのは、一つのドメインモデルでUIから永続データまで直接カバーするのではなく、ドメインモデルの枠組みの中で、目的毎のデータモデルを構築して、これらのデータモデルを連携させて、全体として機能させていく必要があるのではないかという仮定です。&lt;br&gt;その目的のために、仮にドメインモデルを以下のような要素に分解して実現することを考えます。&lt;ul&gt;&lt;li&gt; メンタルデータモデル&lt;br /&gt;&lt;li&gt; アプリケーションデータモデル&lt;br /&gt;&lt;li&gt; 永続データモデル&lt;br /&gt;&lt;li&gt; 集約データモデル&lt;/ul&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-gwHkdxK8DW0/Tth2ptg1zMI/AAAAAAAAAPw/uQqQzuPE-Pw/s1600/domainModel.png" imageanchor="1" style=""&gt;&lt;img border="0" height="318" width="400" src="http://2.bp.blogspot.com/-gwHkdxK8DW0/Tth2ptg1zMI/AAAAAAAAAPw/uQqQzuPE-Pw/s400/domainModel.png" /&gt;&lt;/a&gt;&lt;/div&gt;UXの実現は、利用者の目的を達成するためという軸から導きだされるものなので、永続データモデルに引きづられすぎては本末転倒です。UX専用のメンタルデータモデルを構築します。&lt;br&gt;クラウドアプリケーションでは、複数のデータソースから得られた情報を取捨選択射影して、アプリケーション独自のデータモデルを構築します。アプリケーションの意図に沿っていること、色々なデータソースを融合させるための十分な記述力を持っていること、メンタルデータモデルへの写像が行えること、といった要件を満たす必要があります。&lt;h4&gt;&lt;a name="doc1_id42"&gt;要約エンティティ&lt;/a&gt;&lt;/h4&gt;利用者側からは利用者中心のメンタルモデル、クラウドプラットフォームからは外部データを集約データモデル、さらにアプリケーションがやりたい事を実現するためのアプリケーションデータモデル。このようないくつかのモデルを連携させて仕事をさせるには、ハブとなるモデル要素を軸に据えるのが常道です。&lt;br&gt;このモデル要素として、以前からアイデアとして温めていた要約エンティティ(ステレオタイプはsummery)がぴったりハマるのではないかというのが、今回の気付きになります。&lt;br&gt;要約エンティティは、アプリケーションが必要なさまざまな情報を集計、集約したエンティティです。つまり、元ネタとなるファクトモデルのエンティティではなく、そこから二次的に派生したエンティティとなります。&lt;br&gt;ある意味では、データベースのビューと同じ目的のものですが、問合せをカプセル化したものではなく、アプリケーションの意志で情報を集積、計算、追加していく点が異なります。&lt;h4&gt;&lt;a name="doc1_id45"&gt;事前計算&lt;/a&gt;&lt;/h4&gt;クラウドアプリケーションでは、利用者数、データ規模の双方に対するスケーラビリティが問題となるアプリケーションが当然増えてきます。&lt;br&gt;スマートデバイスからのアクセスでは、より高速なレスポンスが要求されます。&lt;br&gt;クラウドアプリケーションの場合は、アプリケーションの外部にあるさまざまなデータを取り込んで利用するユースケースも考えられます。この場合は、外部のアプリケーションへの通信が発生するため、相応の遅延が発生することになります。複数の外部アプリケーションと連携する場合はさらに大変なことになります。&lt;br&gt;いずれにしても、問合せを受けた契機で、アプリケーションロジックとして問合せ処理を行うのでは、実用的な性能がでない可能性が高いでしょう。&lt;br&gt;この問題へ対応するには、予測される問合せ処理を事前にバックグラウンドで行っておく必要があります。この事前計算の結果を格納する受け皿として要約エンティティが使用できます。&lt;br&gt;以下の図ではドメインイベントを契機に、ドメインデータの値と合わせて、何らかの要約処理を行い要約エンティティに格納しています。このように、利用者が問合せしたタイミングではなく、イベントが発生したタイミングで要約データを計算しておくことで、利用者からの問合せに対して高速にレスポンスを返すことができるようになります&lt;br&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-Sz2WVwLWrQw/Tth2p0RWONI/AAAAAAAAAP8/3hujIbO-rdQ/s1600/summaryEntity.png" imageanchor="1" style=""&gt;&lt;img border="0" height="220" width="400" src="http://4.bp.blogspot.com/-Sz2WVwLWrQw/Tth2p0RWONI/AAAAAAAAAP8/3hujIbO-rdQ/s400/summaryEntity.png" /&gt;&lt;/a&gt;&lt;/div&gt;要約エンティティを導入すると、各種データのスムーズな連携が可能になるのに加えて、問合せ結果を事前計算しておくことによって、問合せのレスポンス時間を向上させるという、クラウドアプリケーションで頻出するユースケースを自然に実現できるようになります。&lt;br&gt;要約データを用いて問合せの性能を上げる手法は以前からあるわけですが、クラウドアプリケーションの場合はより重要な手法になります。&lt;br&gt;要約データは、ある意味ではデータモデルの論理的な一貫性を弱くしてしまうデータを導入することになります。このため、今までは、要約データはできるだけ用いずトランザクションの枠組みの中でSQLによって一括に結合して取得するアプローチが好まれていました。&lt;br&gt;しかし、クラウドアプリケーションのスケーラビリティ要件では、このような強い一貫性を用いるとレスポンス時間に大きな犠牲が出てくるため、逆に一貫性を弱め、いかに適切な事前計算をしておくことによって、実用的なレスポンス時間を確保するのかという点が、重要なアプローチになるわけです。&lt;h4&gt;&lt;a name="doc1_id50"&gt;イベント駆動&lt;/a&gt;&lt;/h4&gt;一般的には、アクターは端末を操作するエンドユーザーであることが多いわけですが、クラウドアプリケーションでは、事情が変わってきます。&lt;br&gt;クラウドアプリケーションでは、今まで以上に他システムとの連携が重要になります。他システムが提供するサービスをRESTなどのプロトコルで使用し、コアコンピタンスの処理のみをアプリケーションで実装することになるでしょう。&lt;br&gt;この他システムもアクターとしてモデル化します。&lt;br&gt;外部センサーやスマートデバイスもクラウドアプリケーションと連携するアクターです。&lt;br&gt;また、アクターに外部センサーやスマートデバイスを加えて、ここから上がってくるイベントのコラボレーションをモデルに加えていけばよいでしょう。&lt;br&gt;アクターが利用者の場合には、基本的には利用者からの問合せや申請に対応するというアプリケーションアーキテクチャになります。&lt;br&gt;しかし、クラウドアプリケーションでは、利用者からの問合せや申請に加えて、他システムからプッシュされてくるさまざまなイベントを蓄積、集計して刻一刻とアプリケーションデータを更新していくことになります。&lt;br&gt;また、上で説明したように利用者からの問合せを予測して事前計算しておくことで、より高速に問合せに対するレスポンスを行うというニーズもあります。&lt;br&gt;このような要件に対応するために、上がってきたイベントをイベントエンティティといったファクトモデルとして記録すると同時に、アプリケーションのユースケースに合わせた要約エンティティにも集計を行い、事前計算をしておくことが有効になると考えられます。&lt;br&gt;また、最近注目されているストリーミングなども、イベント駆動の粒度が小さくなったものと考えることができます。この場合も要約エンティティが有効に機能するはずです。&lt;h4&gt;&lt;a name="doc1_id53"&gt;まとめ&lt;/a&gt;&lt;/h4&gt;要約データ(summary)自体は、新しいアイデアではなくて、大きめのシステムでは広く用いられているものと思いますが、データモデルの正規化という観点からは、あまり望ましいものではなく、どちらかというと日陰者的な扱いではないかと思います。これを一級市民として扱って、UXとイベント駆動を結びつけるハブとして使うと、ぴったり収まるのではないか、というのが今回のアイデアです。&lt;br&gt;設計段階の回避策ではなく、分析段階から積極的に使っていこうということですね。そうすることによって、クラウドにまつわる遅延や障害、スケーラビリティというさまざまな問題をうまく扱えるのではないかということです。こうやって文章にしてみると、地味な改良案ですが、メタモデラー的には面白い気付きになりました。&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7964484936470829118-5506803217038263550?l=modegramming.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://modegramming.blogspot.com/feeds/5506803217038263550/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://modegramming.blogspot.com/2011/12/blog-post.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/5506803217038263550'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/5506803217038263550'/><link rel='alternate' type='text/html' href='http://modegramming.blogspot.com/2011/12/blog-post.html' title='要約エンティティ'/><author><name>asami</name><uri>http://www.blogger.com/profile/12083671403528595185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_4HtJQwbXqEY/S4sSwhKz5fI/AAAAAAAAAFs/IvXW6ca5RGE/S220/profile.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-TnkJaLrMqvY/Tth2pThNOyI/AAAAAAAAAPk/OVjAVUVpmrw/s72-c/modelMap.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7964484936470829118.post-206103394600259174</id><published>2011-11-21T08:36:00.000+09:00</published><updated>2011-11-21T08:36:17.292+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mindmapmodeling'/><title type='text'>「崖っぷちの欧州、ローマの炎上を許すな」のマインドマップとクラス図</title><content type='html'>11月19日(土)に&lt;a href="http://atnd.org/events/21756"&gt;横浜モデリング勉強会&lt;/a&gt;を行いました。&lt;br /&gt;参加者６名で、懇親会も盛り上がりました。&lt;br /&gt;また、会場には&lt;a href="http://www.atware.co.jp/"&gt;(株)アットウェア&lt;/a&gt;様の会議室をお借りしました。&lt;br /&gt;参加された皆さん、アットウェア様、どうもありがとうございました。&lt;br /&gt;&lt;br /&gt;この勉強会で、浅海が作成したモデルを紹介します。&lt;br /&gt;モデルは&lt;a href="http://www.amazon.co.jp/dp/479811748X"&gt;MindmapModeling&lt;/a&gt;の手法で作成しました。(&lt;a href="http://www.slideshare.net/asami224/mindmapmodeling"&gt;勉強会で使用したチュートリアル&lt;/a&gt;)&lt;br /&gt;&lt;br /&gt;モデリングの対象は、JB PRESS誌に掲載されたMartin Wolf氏の記事(FT誌の翻訳)「&lt;a href="http://jbpress.ismedia.jp/articles/-/29621"&gt;崖っぷちの欧州、ローマの炎上を許すな&lt;/a&gt;」です。前回と同様に、時事ネタなのと、いろいろな情報が交錯していて、一見焦点が絞れないところが、モデリングの練習によい感じです。&lt;br /&gt;この記事における現実世界の構造をオブジェクトモデルとして抽出します。&lt;br /&gt;&lt;br /&gt;まず、最初の作業で記事中から単語を抜き出します。&lt;br /&gt;単語を抜き出しながら、登場人物、道具、出来事を中心にMindmapModelingの定めた分類に従って仕分けしていきます。&lt;br /&gt;この結果、できた最初のマインドマップが以下のものです。(図をクリックすると拡大します。)&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-ES8o6iSYjpY/Tsl32DLdy6I/AAAAAAAAAOM/1-JEl_BBBxU/s1600/eu1.png" imageanchor="1" style=""&gt;&lt;img border="0" height="257" width="400" src="http://1.bp.blogspot.com/-ES8o6iSYjpY/Tsl32DLdy6I/AAAAAAAAAOM/1-JEl_BBBxU/s400/eu1.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;次の段階では、抽出した、登場人物、道具、出来事の洗練を行います。&lt;br /&gt;用語の名寄せ、用語の種類(generalization)や部品構成(aggregation)を整理していきます。&lt;br /&gt;また、この段階で区分(powertype)の抽出を開始します。&lt;br /&gt;以上の作業を行った結果のマインドマップは以下のものです。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-r8NshB-wuH8/Tsl32ca9GhI/AAAAAAAAAOY/Di6W3YrYD9M/s1600/eu2.png" imageanchor="1" style=""&gt;&lt;img border="0" height="250" width="400" src="http://2.bp.blogspot.com/-r8NshB-wuH8/Tsl32ca9GhI/AAAAAAAAAOY/Di6W3YrYD9M/s400/eu2.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;このマインドマップを&lt;a href="http://code.google.com/p/simplemodeler/"&gt;SimpleModeler&lt;/a&gt;でクラス図に変換すると以下のものになります。「国」を中心に、ある程度構造化ができていますが、まだまだ中に浮いたクラスがあることが分かります。&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-5Z-ICzDJtPo/Tsl34KltsmI/AAAAAAAAAO8/Z-HWhg9Gh9A/s1600/eu2-oo.png" imageanchor="1" style=""&gt;&lt;img border="0" height="52" width="400" src="http://1.bp.blogspot.com/-5Z-ICzDJtPo/Tsl34KltsmI/AAAAAAAAAO8/Z-HWhg9Gh9A/s400/eu2-oo.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;次の段階では、対象となる世界の動的な側面を捉える出来事や物語を整理していきます。&lt;br /&gt;出来事や物語を洗練していくことによって、出来事や物語における登場人物や道具の役割が明確化され、より登場人物や道具の構造をさらに洗練させることができます。&lt;br /&gt;出来事や物語で抽出した役割は、役割(role)としてモデル化して「役割」構造枝に配置し、役割の持つ構造を洗練していきます。&lt;br /&gt;&lt;br /&gt;今回は、EUの「中心にいる国々」(事実上、ドイツですが)が主役の物語「欧州連合を救う」と、ギリシャやイタリアなど「支援を受ける側」が主役の物語「経済破綻を回避する」の2つの物語を軸にモデルを整理していきました。&lt;br /&gt;&lt;br /&gt;今回のモデルでもう一点ポイントになるのがドメイン・ルール(Domain Rule)、制約条件です。&lt;br /&gt;記事からは「緊縮財政政策 ⇒ 内需が弱くなる」、&lt;br /&gt;「景気が回復しない ⇒ 投資家の信頼感を取り戻す可能性は低い」、&lt;br /&gt;「構造改革 ⇒ 労働市場に影響を及ぼす」、&lt;br /&gt;「労働市場に悪影響 ⇒ 社会的・政治的な混乱」、&lt;br /&gt;「社会的・政治的な混乱 ⇒ 投資家の信頼感は揺らぐ」、&lt;br /&gt;「競争力が回復する ⇒ 人員解雇と名目賃金下落をもたらす」、&lt;br /&gt;「人員解雇と名目賃金下落 ⇒ 失業と社会不安、債権者の不安感」といったルールが抽出できます。&lt;br /&gt;&lt;br /&gt;救う側であるEUの「中心にいる国々」も、「支援を受ける側」もこれらの制約条項の上で、金融政策、財政政策、労働政策などを立案、遂行していく必要があります。この記事の場合、こういった制約群で合成される非常に厳しい全体制約が物語の遂行をほぼ実現不可能にしているという絶望感が記事の重要なテーマと考えられます。&lt;br /&gt;逆に、針の穴を通すほどの小さいストライクゾーンとなる、実現可能な組合せは何かというのが、テーマとしてあぶり出されてくるわけですね。&lt;br /&gt;この「実現可能な制約条件の組合せ」の抽出は、システムを実現する上での重要なモデル要素なので、MindmapModelingでもモデルを記述することができるようになっています。これが、BOI構造枝「規則」(Domain Rule)というわけです。&lt;br /&gt;&lt;br /&gt;MindmapModelingではBOI構造枝「規則」に記述するDomain Ruleの命名法や構造などは特に定めていません。現状では、OCLのような非常に限定した形でしか、制約を記述して実装に落し込む手法が一般的になっていないからです。&lt;br /&gt;(ルールエンジンなどの商用ミドルウェアやJSR 94 Java Rule Engine APIなどは存在していて一部では活用されていると思いますが)&lt;br /&gt;&lt;br /&gt;ただ、最近は関数型言語が実装言語として視野に入ってきたので、このあたりとの接続を念頭において、「規則」の記述方法について文法の拡張を行うことを考えています。&lt;br /&gt;今回は、論理結合子「⇒」(ならば, conditional, material implication)を使ってみました。最終的には、実装の自動生成時に関数型言語が扱える論理式を自動生成するのが目標です。&lt;br /&gt;&lt;br /&gt;とはいえ、「緊縮財政政策 ⇒ 内需が弱くなる」という論理式は「緊縮財政政策」ならば必ず「内需が弱くなる」ということですが、現実には100%ということはないので、現実世界のモデリングには使いづらい面があります。参考情報に留めるのか、様相論理の可能性演算子(◇, possibility operator)といったものを導入するか、色々と考えてみたいところです。&lt;br /&gt;&lt;br /&gt;以上の作業の結果、作成したマインドマップが以下のものです。&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-3fCTF8vD7BQ/Tsl33EFwH-I/AAAAAAAAAOk/ywPrQELHvrE/s1600/eux.png" imageanchor="1" style=""&gt;&lt;img border="0" height="296" width="400" src="http://4.bp.blogspot.com/-3fCTF8vD7BQ/Tsl33EFwH-I/AAAAAAAAAOk/ywPrQELHvrE/s400/eux.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;このマインドマップをSimpleModelerでクラス図に変換したものが以下の図です。&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-NHwuF2dqYxw/Tsl4FU-5jpI/AAAAAAAAAPM/DJ3a5Ckelmc/s1600/eux-oo.png" imageanchor="1" style=""&gt;&lt;img border="0" height="89" width="400" src="http://2.bp.blogspot.com/-NHwuF2dqYxw/Tsl4FU-5jpI/AAAAAAAAAPM/DJ3a5Ckelmc/s400/eux-oo.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;以上のマインドマップとクラス図が勉強会で作成したものです。&lt;br /&gt;&lt;br /&gt;クラス図にしてみると、名寄の甘いところや、モデル要素のステレオタイプの選択などで問題があることが分かります。&lt;br /&gt;そこで、SimpleModelerでのクラス図生成を繰り返しながら洗練したマインドマップと、このマインドマップから&lt;a href="http://code.google.com/p/simplemodeler/"&gt;SimpleModeler&lt;/a&gt;を使って生成したクラス図は以下のものです。&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-Yzj6ZyWqh8U/Tsl33l4EFjI/AAAAAAAAAOw/nGMI2mjN9UA/s1600/euxx.png" imageanchor="1" style=""&gt;&lt;img border="0" height="302" width="400" src="http://2.bp.blogspot.com/-Yzj6ZyWqh8U/Tsl33l4EFjI/AAAAAAAAAOw/nGMI2mjN9UA/s400/euxx.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-RtAKjvchZIk/Tsl4FaKOryI/AAAAAAAAAPY/ezq3W6iYzSY/s1600/euxx-oo.png" imageanchor="1" style=""&gt;&lt;img border="0" height="65" width="400" src="http://3.bp.blogspot.com/-RtAKjvchZIk/Tsl4FaKOryI/AAAAAAAAAPY/ezq3W6iYzSY/s400/euxx-oo.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;記事における現実世界の構造がそれなりに上手くとらえられていると思います。&lt;br /&gt;&lt;br /&gt;このように記事を詳細にモデル化すると、記事の内容がより深く理解できますね。&lt;br /&gt;&lt;br /&gt;「支援を受ける側」が取り得る方法は、制約条件の組合せからほぼ:&lt;br /&gt;&lt;ul&gt;&lt;li&gt; 緊縮財政、構造改革する。&lt;br /&gt;&lt;li&gt; 緊縮財政、構造改革による内需の縮小は、外需の取り込みでカバーする。&lt;br /&gt;&lt;li&gt; 緊縮財政、構造改革による社会の不安定化により、投資家が投資を引き上げないために不安感を払拭する対策を行う。&lt;br /&gt;&lt;/ul&gt;しかないことが分かります。&lt;br /&gt;&lt;br /&gt;EU圏外の国から外需の取り込みを行うことも、社会の不安定化を払拭する施策も、相当難しそうですが、このあたりが今後のEUの動向を見定めるポイントかもしれません。&lt;br /&gt;&lt;br /&gt;緊縮財政、構造改革を行う国が唯一取れる成長戦略が外需の取り込みである以上、自国通貨の切り下げ、相手国関税、非関税障壁の撤廃が最重要戦略となるわけで、(EUは入れてもらえませんが)最近TPPが政治的なイシューになっている背景がなんとなく見えてきますね。(記事の内容からの推論なので、感想の妥当性は無保証ですw)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7964484936470829118-206103394600259174?l=modegramming.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://modegramming.blogspot.com/feeds/206103394600259174/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://modegramming.blogspot.com/2011/11/blog-post.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/206103394600259174'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/206103394600259174'/><link rel='alternate' type='text/html' href='http://modegramming.blogspot.com/2011/11/blog-post.html' title='「崖っぷちの欧州、ローマの炎上を許すな」のマインドマップとクラス図'/><author><name>asami</name><uri>http://www.blogger.com/profile/12083671403528595185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_4HtJQwbXqEY/S4sSwhKz5fI/AAAAAAAAAFs/IvXW6ca5RGE/S220/profile.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-ES8o6iSYjpY/Tsl32DLdy6I/AAAAAAAAAOM/1-JEl_BBBxU/s72-c/eu1.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7964484936470829118.post-3360154757238880811</id><published>2011-11-19T12:34:00.000+09:00</published><updated>2011-11-19T12:34:39.180+09:00</updated><title type='text'>横浜モデリング勉強会 (第2回)</title><content type='html'>今日(11/19)のモデリング勉強会の情報です。&lt;br /&gt;&lt;br /&gt;&lt;a href="http://atnd.org/events/21756"&gt;http://atnd.org/events/21756&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;今回モデリングするのは以下のWeb記事です。&lt;br /&gt;&lt;br /&gt;テーマ: &amp;nbsp;崖っぷちの欧州、ローマの炎上を許すな&lt;br /&gt;&lt;div&gt;&lt;a href="http://jbpress.ismedia.jp/articles/-/29621"&gt;http://jbpress.ismedia.jp/articles/-/29621&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;モデリングは記事の問題領域であるドメインモデルを作成を目標にします。&lt;br /&gt;&lt;ul&gt;&lt;li&gt;問題領域の構造を、エンジニアでない人が理解できるで構築している。&lt;/li&gt;&lt;li&gt;プログラムに落し込むことができる。&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;モデリングは各自のお好きなモデリング手法で行います。&lt;/div&gt;&lt;div&gt;一時間に一度程度、作成途中のモデルを見ながら議論します。&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;初学者の方は、MindmapModelingをお勧めします。&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.slideshare.net/asami224/mindmapmodeling"&gt;MindmapModelingチュートリアル&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7964484936470829118-3360154757238880811?l=modegramming.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://modegramming.blogspot.com/feeds/3360154757238880811/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://modegramming.blogspot.com/2011/11/2.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/3360154757238880811'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/3360154757238880811'/><link rel='alternate' type='text/html' href='http://modegramming.blogspot.com/2011/11/2.html' title='横浜モデリング勉強会 (第2回)'/><author><name>asami</name><uri>http://www.blogger.com/profile/12083671403528595185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_4HtJQwbXqEY/S4sSwhKz5fI/AAAAAAAAAFs/IvXW6ca5RGE/S220/profile.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7964484936470829118.post-236756053132412141</id><published>2011-10-31T22:34:00.002+09:00</published><updated>2011-11-01T04:45:21.225+09:00</updated><title type='text'>「TPP議論の本質はこれだ！」のマインドマップとクラス図</title><content type='html'>10月29日(土)に&lt;a href="http://atnd.org/events/20884"&gt;横浜モデリング勉強会&lt;/a&gt;を行いました。&lt;br /&gt;札幌サテライトから2名参加があり合計6名の参加でした。&lt;br /&gt;参加された皆さん、どうもありがとうございました。&lt;br /&gt;&lt;br /&gt;この勉強会で、浅海が作成したモデルを紹介します。&lt;br /&gt;モデルは&lt;a href="http://www.amazon.co.jp/dp/479811748X"&gt;MindmapModeling&lt;/a&gt;の手法で作成しました。(&lt;a href="http://www.slideshare.net/asami224/mindmapmodeling"&gt;勉強会で使用したチュートリアル&lt;/a&gt;)&lt;br /&gt;&lt;br /&gt;モデリングの対象は、田原総一朗氏のブログ記事「&lt;a href="http://news.livedoor.com/article/detail/5962027/"&gt;ＴＰＰ議論の本質はこれだ！&lt;/a&gt;」です。時事ネタなのと、いろいろな情報が交錯していて、掴みどころがないのが、モデリングの練習によい感じです。&lt;br /&gt;この記事における現実世界の構造をオブジェクトモデルとして抽出するという趣旨です。&lt;br /&gt;&lt;br /&gt;まず、最初の作業で記事中から単語を抜き出します。&lt;br /&gt;単語を抜き出しながら、登場人物、道具、出来事を中心にMindmapModelingの定めた分類に従って仕分けしていきます。&lt;br /&gt;この結果、できた最初のマインドマップが以下のものです。(図をクリックすると拡大します。)&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-nrHKxTK_BWs/Tq55BPoGXgI/AAAAAAAAAN4/hO61Au2k8Lw/s1600/tpp.png" imageanchor="1"&gt;&lt;img border="0" height="282" src="http://3.bp.blogspot.com/-nrHKxTK_BWs/Tq55BPoGXgI/AAAAAAAAAN4/hO61Au2k8Lw/s400/tpp.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;次の段階では、抽出した、登場人物、道具、出来事の洗練を行います。&lt;br /&gt;用語の名寄せ、用語の種類(generalization)や部品構成(aggregation)を整理していきます。&lt;br /&gt;また、この段階で区分(powertype)の抽出を開始します。&lt;br /&gt;以上の作業を行った結果のマインドマップは以下のものです。&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-WUvOrrgVBDk/Tq526-v5e0I/AAAAAAAAANM/8BS730c9vg8/s1600/tpp10.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="237" src="http://3.bp.blogspot.com/-WUvOrrgVBDk/Tq526-v5e0I/AAAAAAAAANM/8BS730c9vg8/s400/tpp10.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;次の段階では、対象となる世界の動的な側面を捉える出来事や物語を整理していきます。&lt;br /&gt;出来事や物語を洗練していくことによって、出来事や物語における登場人物や道具の役割が明確化され、より登場人物や道具の構造をさらに洗練させることができます。&lt;br /&gt;出来事や物語で抽出した役割は、役割(role)としてモデル化して「役割」構造枝に配置し、役割の持つ構造を洗練していきます。&lt;br /&gt;&lt;br /&gt;以上の作業の結果、作成したマインドマップが以下のものです。&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-RG4URQSt7D8/Tq53Ao6fonI/AAAAAAAAANU/pVd8xIBCP_0/s1600/tpp2.png" imageanchor="1"&gt;&lt;img border="0" height="251" src="http://3.bp.blogspot.com/-RG4URQSt7D8/Tq53Ao6fonI/AAAAAAAAANU/pVd8xIBCP_0/s320/tpp2.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;モデリング勉強会での作業はここまででした。&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;その後、このマインドマップをSimpleModelerでクラス図に変換したものが以下のクラス図です。(クリックすると拡大します。)&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;クラス図にしてみると、まだまだ抜けているところがあることがよく分かります。&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;モデルとして欠陥があるわけではなさそうですが、名寄せが甘いところや、時間切れでモデルに記述しきれなかったところが明確になりました。&lt;/div&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-6uTPmX0JH1c/Tq53H7ZHi6I/AAAAAAAAANc/Ok-jptl6Kgg/s1600/tpp2ClassDiagramtpp2Detail.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="36" src="http://1.bp.blogspot.com/-6uTPmX0JH1c/Tq53H7ZHi6I/AAAAAAAAANc/Ok-jptl6Kgg/s400/tpp2ClassDiagramtpp2Detail.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;そこで、SimpleModelerでのクラス図生成を繰り返しながら洗練したマインドマップが以下のものです。&lt;/div&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-m68JOc0Yll4/Tq53LZ-FhqI/AAAAAAAAANk/dE5ocbudQsY/s1600/tppsm.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="272" src="http://3.bp.blogspot.com/-m68JOc0Yll4/Tq53LZ-FhqI/AAAAAAAAANk/dE5ocbudQsY/s400/tppsm.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;このマインドマップをSimpleModelerを使ってクラス図に変換したものが以下のクラス図です。(クリックすると拡大します。)&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;記事における現実世界の構造がそれなりに上手くとらえられていると思います。&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;短い記事ですが、丹念にモデル化していると存外大きな構造が背景にあることが分かります。&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: -webkit-auto;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-a5aAX4GOQ8Q/Tq53OsoXf3I/AAAAAAAAANs/gYipHPL7pKU/s1600/ClassDiagramtppsmDetail.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="75" src="http://2.bp.blogspot.com/-a5aAX4GOQ8Q/Tq53OsoXf3I/AAAAAAAAANs/gYipHPL7pKU/s400/ClassDiagramtppsmDetail.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: -webkit-auto;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: -webkit-auto;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;物語は記事中で一番重要視していると思われる「アメリカのアジア戦略」を抽出しましたが、時間があれば「アメリカの輸出増加戦略」や「日本のTPP外交戦略」というような物語を加えるとより内容が充実してくると思います。&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7964484936470829118-236756053132412141?l=modegramming.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://modegramming.blogspot.com/feeds/236756053132412141/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://modegramming.blogspot.com/2011/10/tpp.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/236756053132412141'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/236756053132412141'/><link rel='alternate' type='text/html' href='http://modegramming.blogspot.com/2011/10/tpp.html' title='「TPP議論の本質はこれだ！」のマインドマップとクラス図'/><author><name>asami</name><uri>http://www.blogger.com/profile/12083671403528595185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_4HtJQwbXqEY/S4sSwhKz5fI/AAAAAAAAAFs/IvXW6ca5RGE/S220/profile.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-nrHKxTK_BWs/Tq55BPoGXgI/AAAAAAAAAN4/hO61Au2k8Lw/s72-c/tpp.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7964484936470829118.post-4085515568705707612</id><published>2011-10-29T09:37:00.000+09:00</published><updated>2011-10-29T09:37:43.522+09:00</updated><title type='text'>モデリング勉強会</title><content type='html'>今日(10/29)のモデリング勉強会の情報です。&lt;br /&gt;&lt;br /&gt;&lt;a href="http://atnd.org/events/20884"&gt;http://atnd.org/events/20884&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;今回モデリングするのは以下のブログ記事です。&lt;br /&gt;&lt;br /&gt;テーマ: &amp;nbsp;TPP議論の本質はこれだ!&lt;br /&gt;&lt;div&gt;&lt;a href="http://news.livedoor.com/article/detail/5962027/"&gt;http://news.livedoor.com/article/detail/5962027/&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;モデリングは各自のお好きなモデリング手法で行います。&lt;/div&gt;&lt;div&gt;一時間に一度程度、作成途中のモデルを見ながら議論します。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;初学者の方は、MindmapModelingをお勧めします。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.slideshare.net/asami224/mindmapmodeling"&gt;MindmapModelingチュートリアル&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7964484936470829118-4085515568705707612?l=modegramming.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://modegramming.blogspot.com/feeds/4085515568705707612/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://modegramming.blogspot.com/2011/10/blog-post_29.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/4085515568705707612'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/4085515568705707612'/><link rel='alternate' type='text/html' href='http://modegramming.blogspot.com/2011/10/blog-post_29.html' title='モデリング勉強会'/><author><name>asami</name><uri>http://www.blogger.com/profile/12083671403528595185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_4HtJQwbXqEY/S4sSwhKz5fI/AAAAAAAAAFs/IvXW6ca5RGE/S220/profile.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7964484936470829118.post-2252144990048936502</id><published>2011-10-29T09:23:00.000+09:00</published><updated>2011-10-29T09:23:59.090+09:00</updated><title type='text'>クラウド時代のデータアーキテクチャとモデリング</title><content type='html'>クラウド時代のデータアーキテクチャとモデリングについてちょっと思いついたことがあるのでメモ。&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/--7ZS67TZLH0/Tqs7TknyaYI/AAAAAAAAAM8/Ly_yK618I3g/s1600/clouddataarch.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="230" src="http://1.bp.blogspot.com/--7ZS67TZLH0/Tqs7TknyaYI/AAAAAAAAAM8/Ly_yK618I3g/s400/clouddataarch.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;br /&gt;&lt;/div&gt;クラウドアプリケーションが従来のアプリケーションと異なる点の一つは、クラウド上に遍在する様々なデータをマッシュアップして使用することになるという点です。&lt;br /&gt;自前で管理するデータだけでなく外部データを編みこんだドメインモデルに対して、アプリケーションが操作を行うことになります。&lt;br /&gt;また、スケーラビリティを確保するため、CQRSのように参照系と更新系をアーキテクチャレベルで分割していく形が基本になるでしょう。&lt;br /&gt;これは、自前データのサイズが巨大になる場合への対応にも有効ですが、外部データとの連携では必須のアーキテクチャです。自前データが巨大にならない普通のアプリケーションでも、外部データとの連携を行うのであれば、このアーキテクチャを採るのが得策です。&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;ドメインモデル&lt;/h3&gt;このアーキテクチャの上でドメインモデルは、以下の3つの種類に分類するのがよいのではないかというのがアイデア。&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Application Domain&lt;/li&gt;&lt;li&gt;Actor Domain&lt;/li&gt;&lt;li&gt;Fact Domain&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;Application Domainは、アプリケーションが操作するドメイン。自前データと外部データをマッシュアップして見せます。&lt;/div&gt;&lt;div&gt;従来のドメインモデルとの違いは、外部データをマッシュアップすること。マッシュアップを行う場合、更新系を含めると実現方法が大変になってくるので、参照系を中心にするとよいでしょう。都合のよいことに参照系と更新系を分離するアーキテクチャにもマッチしています。&lt;/div&gt;&lt;div&gt;従来技術でもRDBMSのViewなどでこういった事が可能ですが、これをもっとアーキテクチャレベルで大掛かりにやるイメージです。(そういう意味ではデータベースの3層スキーマが近しいかも。)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;外部データは、Actor Domainとしてモデル化します。Actor Objectは、アプリケーション外にあるオブジェクト(の代理オブジェクト)という意味ですが、このドメインモデル版という意図でActor Domainという名前にしてみました。&lt;/div&gt;&lt;div&gt;Actor Objectの場合、自前のオブジェクトでないので、決められた範囲でお願いはできるけど自由に操作できないという処理上の制約が出てきます。&lt;/div&gt;&lt;div&gt;Actor Domainもそういった制約を持ったドメインモデルをイメージしています。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;そして、Actor Domainの外側にFact Domainを持ってきました。&lt;/div&gt;&lt;div&gt;Fact Domainは、クラウド上で発生する無数のイベントの生データをイメージしています。たとえばアプリケーションのログや、データベースのジャーナルなどです。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Actor Domainはアプリケーションの外部で、Fact Domainのデータを集約し、意味を付加したモデルとしてモデルインスタンスが公開されています。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Application Domainは、このAcotr Domainのインスタンスを、自前データとマッシュアップして、アプリケーションに取って意味のあるモデルのインスタンスとして、アプリケーションに提供します。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;h3&gt;更新系&lt;/h3&gt;更新系には、Application Commandというモジュールを用意しました。(Commandというのは仮です。他によい名前があったら取り替えると思います。)&lt;br /&gt;Application Commandは自前のデータの更新を中心に、Application Domainへの更新依頼、Fact Domainの情報提供を行います。&lt;br /&gt;Application Domainへの更新依頼はあまり多くないという仮定で点線にしてみました。&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;モデリング技術&lt;/h3&gt;こういったデータアーキテクチャを採る場合のモデリング技術として、どうも文書モデリング(SGML, XML系)が有効でないかというのが、データアーキテクチャと同時に思いついたアイデア。&lt;br /&gt;従来アプリケーションでは、データモデル/オブジェクトモデルがモデリングの中心でしたが、ここまで説明してきたようなマッシュアップが基本となるデータアーキテクチャでは、異なったセマンティクスのモデルをマッシュアップする基盤として文書モデリングが重要になってくるのではないかということです。&lt;br /&gt;2000年頃にも、こういう話題がよく出たと思いますが、クラウド時代になって改めて、この技術を適用する形が見えてきた感触です。&lt;br /&gt;ただし、今回はXMLという文脈でなく、関数型という文脈ではないかというのが、今回のアイデアの軸。関数型プログラミングと文書モデリングの相性は相当よさそうです。&lt;br /&gt;XMLはデータ表現形式としてはよいのですが、データ操作体系としてはまだまだ不十分でした。ここを関数型言語ですっきりと記述することが可能になってきたのは一つミッシングリンクが埋まってきた感じです。&lt;br /&gt;&lt;br /&gt;オブジェクトモデル、データモデル、文書モデル、関数モデル。&lt;br /&gt;Application Domainのメタモデルとして、4つのモデルをどのように配合していくとよいのか。まだまだノーアイデアですが、未開拓の領域だけに色々と面白そうです。&lt;br /&gt;クラウドも現時点では、プラットフォーム技術やフレームワーク、プログラミング言語といった実装よりの技術に焦点があっていますが、次の段階ではこういったモデリング技術の所に焦点が移ってくるのではないかと考えています。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7964484936470829118-2252144990048936502?l=modegramming.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://modegramming.blogspot.com/feeds/2252144990048936502/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://modegramming.blogspot.com/2011/10/blog-post.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/2252144990048936502'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/2252144990048936502'/><link rel='alternate' type='text/html' href='http://modegramming.blogspot.com/2011/10/blog-post.html' title='クラウド時代のデータアーキテクチャとモデリング'/><author><name>asami</name><uri>http://www.blogger.com/profile/12083671403528595185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_4HtJQwbXqEY/S4sSwhKz5fI/AAAAAAAAAFs/IvXW6ca5RGE/S220/profile.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/--7ZS67TZLH0/Tqs7TknyaYI/AAAAAAAAAM8/Ly_yK618I3g/s72-c/clouddataarch.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7964484936470829118.post-5765321305959351378</id><published>2011-09-19T21:00:00.000+09:00</published><updated>2011-09-19T21:00:10.702+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='simplemodeler'/><category scheme='http://www.blogger.com/atom/ns#' term='g4'/><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>RESTのFeedを一覧表示するActivityの生成</title><content type='html'>8月27,28日に開催された&lt;a href="http://www.facebook.com/home.php?sk=group_225282024151633"&gt;クラウド温泉@小樽&lt;/a&gt;のセッション、「クラウドアプリケーション(App Engine＆Android)自動生成 - SimpleModeler/g3/g4デモ」でのSimpleModelerからAndroidアプリの自動生成のデモの話の続きです。&lt;br&gt;&lt;br /&gt;SimpleModelerでは、アプリケーション開発のベースとなるドメインモデルの実装を「&lt;a href="http://modegramming.blogspot.com/2011/07/simplemodeler.html"&gt;自動コーディング&lt;/a&gt;」します。この部分はドメインモデルが決まれば、プラットフォーム上での実装はほぼ決まるので自動生成の格好のターゲットです。逆に、この部分を手組みでコーディングしていると相当の工数が必要となります。プログラム開発の生産性を上げるためには、この部分の生産性向上が重要になってきます。&lt;br&gt;&lt;br /&gt;ただし、エンティティに対するCRUD処理については自動生成である程度のモノを生成可能です。アプリケーション部分のサンプルという意味もこめて、データに対するCRUD処理を行なうActivityを生成する予定で、一部実現しています。&lt;br&gt;&lt;br /&gt;現在SimpleModelerが自動生成しているのは、サーバー上に格納されているエンティティCustomerをREST経由でアクセスして一覧表示を行うプログラムが以下のCustomerRestViewActivityです。&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;package com.demo;&lt;br /&gt;&lt;br /&gt;import android.content.Context;&lt;br /&gt;import android.os.Bundle;&lt;br /&gt;import java.math.*;&lt;br /&gt;import java.util.*;&lt;br /&gt;import org.goldenport.android.*;&lt;br /&gt;import org.goldenport.android.traits.ListViewTrait;&lt;br /&gt;&lt;br /&gt;public class CustomerRestViewActivity extends GActivity&amp;lt;DemoController&amp;gt; {&lt;br /&gt;    &lt;br /&gt;    // @LayoutView(R.id.header)&lt;br /&gt;    // TextView mHeader;&lt;br /&gt;    // @ResourceString(R.string.header)&lt;br /&gt;    // String mHeaderLabel;&lt;br /&gt;    // @ResourceColor(R.color.header)&lt;br /&gt;    // Color mHeaderColor;&lt;br /&gt;    // @IntentExtra("message")&lt;br /&gt;    // String mMessage;&lt;br /&gt;    &lt;br /&gt;    public CustomerRestViewActivity() {&lt;br /&gt;        addTrait(new ListViewTrait());&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    @Override&lt;br /&gt;    protected void onCreate(Bundle savedInstanceState) {&lt;br /&gt;        super.onCreate(savedInstanceState);&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    @Override&lt;br /&gt;    protected int get_Layout_id() {&lt;br /&gt;        return R.layout.customer_rest_view;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    @Override&lt;br /&gt;    protected void onStart() {&lt;br /&gt;        super.onStart();&lt;br /&gt;    //    if (mMessage != null) {&lt;br /&gt;    //        mHeader.setText(mMessage);&lt;br /&gt;    //    } else {&lt;br /&gt;    //        mHeader.setText(mHeaderLabel);&lt;br /&gt;    //    }&lt;br /&gt;        set_list_adapter(gcontroller.getCustomerRestFeedAdapter());&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h4&gt;&lt;a name="doc1_id24"&gt;GActivity&lt;/a&gt;&lt;/h4&gt;&lt;br /&gt;CustomerRestViewActivityは、サーバー上に格納されているエンティティCustomerをRESTでアクセスしてListViewの一覧として表示するActivityです。基底クラスはGActivityで、型パラメータとしてDemoアプリケーションのコントローラであるDemoControllerを指定しています。&lt;br&gt;&lt;br /&gt;org.goldenport.android.GActivityが、g4におけるActivityの基底クラスです。主に以下の機能を提供しています。&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt; DI&lt;br /&gt;&lt;li&gt; コントローラクラスの自動バインド&lt;br /&gt;&lt;li&gt; トレイトによる機能拡張&lt;br /&gt;&lt;li&gt; 非同期更新処理&lt;/ul&gt;&lt;h4&gt;&lt;a name="doc1_id42"&gt;DI(Dependency Injection)&lt;/a&gt;&lt;/h4&gt;g4では、Google Guice (without AOP)を用いたDIコンテナ機能を提供しています。XMLで定義された各種ViewやリソースをActivityのインスタンス変数に自動インジェクトすることができます。&lt;br&gt;自動生成されたCustomerRestViewActivityを、自前で拡張するためのヒントとして以下のコメントが入っています。&lt;br&gt;この機能は次回の記事で説明することにします。&lt;br&gt;&lt;pre class="java" name="code"&gt;// @LayoutView(R.id.header)&lt;br /&gt;    // TextView mHeader;&lt;br /&gt;    // @ResourceString(R.string.header)&lt;br /&gt;    // String mHeaderLabel;&lt;br /&gt;    // @ResourceColor(R.color.header)&lt;br /&gt;    // Color mHeaderColor;&lt;br /&gt;    // @IntentExtra("message")&lt;br /&gt;    // String mMessage;&lt;br /&gt;&lt;/pre&gt;&lt;h4&gt;&lt;a name="doc1_id48"&gt;コントローラクラスの自動バインド&lt;/a&gt;&lt;/h4&gt;g4では、画面表示を行うクラスであるGActivity(Activityのサブクラス)から、アプリケーション・ロジックを分離してコントローラとして実装します。コントローラはGControllerのサブクラスになります。&lt;br&gt;Activityからアプリケーションロジックを分離して、コントローラ側で実現することにより、以下の効果を期待しています。&lt;br&gt;&lt;ul&gt;&lt;li&gt; アプリケーション全体のロジックをコントローラに集中させることで、アプリケーションの見通しを良くし、拡張性、保守性を高める。&lt;br /&gt;&lt;li&gt; GUIを経由しないで、アプリケーションロジックのユニットを可能にする。&lt;br /&gt;&lt;li&gt; アプリケーションロジックを複数のActivityから共用できる。&lt;/ul&gt;GActivityでは、コントローラクラスを自動的にインジェクトするので、GActivityの実装では、特に初期化処理なしでコントローラを参照して使うことができます。　&lt;br&gt;生成されたonStartメソッドにはヒントのコメントがあります。この不要なコメントを削除したonStartメソッドは以下のものになります。&lt;br&gt;&lt;pre name="code" class="java"&gt;@Override&lt;br /&gt;    protected void onStart() {&lt;br /&gt;        super.onStart();&lt;br /&gt;        set_list_adapter(gcontroller.getCustomerRestFeedAdapter());&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;「super.onStart()」はお約束。&lt;br&gt;set_list_adapterメソッドで、コントローラから返されるListAdapterを設定しています。&lt;br&gt;GActivityで定義しているインスタンス変数gcontrollerから参照しているコントローラ(DemoController)から、ドメインエンティティCustomerをRESTのフィードとしてアクセスするListAdapterを取得しています。&lt;br&gt;このListAdapterは、バックエンドにページング付きのREST通信と通信結果のキャッシュ機能を持っています。この機能を実現するために、&lt;a href="#doc1_id71"&gt;SimpldeModelerが生成するAndroidコード&lt;/a&gt;で説明したとおり、ActivityからRESTドライバにいたるまで相当数のコードが自動生成されています。また、g4ベースでサーバサイドのコードも自動生成していることは、&lt;a href="http://modegramming.blogspot.com/2011/07/simplemodeler.html"&gt;SimpleModeler (クラウド温泉@小樽)&lt;/a&gt;で触れました。このあたりのメカニズムはいずれ紹介したいと思います。&lt;h4&gt;&lt;a name="doc1_id69"&gt;トレイトによる機能拡張&lt;/a&gt;&lt;/h4&gt;ActivityにListViewやGralleryなどを操作するロジックをハードコーディングしてしまうと、ロジックを他の目的に再利用させることができません。&lt;br&gt;これらの機能を持つ基底クラスを作るのが次善策ですが、拡張性や保守性に問題があります。&lt;br&gt;この問題を解決するために、g4ではScalaのトレイトライクなメカニズムを導入しました。&lt;br&gt;ListViewTraitは、ListViewを操作する機能を持つトレイトです。GActivityのaddTraitメソッドによりListViewTraitを追加することによりGActivityにListViewを操作する機能が追加されます。&lt;br&gt;以下のようにコンストラクタでトレイトListViweTraitを追加しています。&lt;br&gt;&lt;pre name="code" class="java"&gt;public CustomerRestViewActivity() {&lt;br /&gt;        addTrait(new ListViewTrait());&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;h4&gt;&lt;a name="doc1_id75"&gt;非同期更新処理&lt;/a&gt;&lt;/h4&gt;ListViewTraitが内部で自動的にハンドリングしているので、CustomerRestViewActivityには直接みえていません。&lt;br&gt;ListViewTraitが、一覧データのローディング時にプログレスバーを画面上に表示し、ローディングが完了した時点で表示を終了する処理を行っています。&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7964484936470829118-5765321305959351378?l=modegramming.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://modegramming.blogspot.com/feeds/5765321305959351378/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://modegramming.blogspot.com/2011/09/restfeedactivity.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/5765321305959351378'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/5765321305959351378'/><link rel='alternate' type='text/html' href='http://modegramming.blogspot.com/2011/09/restfeedactivity.html' title='RESTのFeedを一覧表示するActivityの生成'/><author><name>asami</name><uri>http://www.blogger.com/profile/12083671403528595185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_4HtJQwbXqEY/S4sSwhKz5fI/AAAAAAAAAFs/IvXW6ca5RGE/S220/profile.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7964484936470829118.post-460609499568054326</id><published>2011-09-01T19:19:00.000+09:00</published><updated>2011-09-01T19:19:12.147+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='simplemodeler'/><category scheme='http://www.blogger.com/atom/ns#' term='g4'/><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>SimpldeModelerが生成するAndroidコード</title><content type='html'>8月27,28日に開催された&lt;a href="http://www.facebook.com/home.php?sk=group_225282024151633"&gt;クラウド温泉@小樽&lt;/a&gt;では、「クラウドアプリケーション(App Engine＆Android)自動生成?SimpleModeler/g3/g4デモ」のセッションで、SimpleModelerからAndroidアプリの自動生成のデモを行いました。&lt;br /&gt;&lt;br /&gt;クラウド温泉＠小樽に向けてブログに書いてきたものを実演しました。&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt; &lt;a href="http://modegramming.blogspot.com/2011/07/simplemodeler.html"&gt;SimpleModeler (クラウド温泉＠小樽)&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt; &lt;a href="http://modegramming.blogspot.com/2011/07/g3.html"&gt;g3 (クラウド温泉＠小樽)&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt; &lt;a href="http://modegramming.blogspot.com/2011/07/g4.html"&gt;g4 (クラウド温泉＠小樽)&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt; &lt;a href="http://modegramming.blogspot.com/2011/06/blog-post.html"&gt;クラウド温泉＠小樽&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;デモに使ったモデルは以下のCSV、demo.csvをコンバートして生成したDEACustomer.java、DEEBuy.java、DERGoods.javaの3つのScala DSLで記述したものです。&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="background-color: #cccccc;"&gt;demo.csv &lt;/span&gt;&lt;br /&gt;&lt;pre class="java" name="code"&gt;#actor,parts,attrs&lt;br /&gt;customer,,phone&lt;br /&gt;#resource&lt;br /&gt;goods,,note&lt;br /&gt;#event&lt;br /&gt;buy,customer;goods&lt;br /&gt;&lt;/pre&gt;そのうちの一つ、DEACustomer.javaのソースコードは以下のものです。DEEBuy.javaとDERGoods.javaもだいたい同じコードになります。&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="background-color: #cccccc;"&gt;DEACustomer.java&lt;/span&gt;&lt;span&gt;&lt;/span&gt; &lt;br /&gt;&lt;pre class="java" name="code"&gt;package com.demo&lt;br /&gt;&lt;br /&gt;import org.simplemodeling.dsl._&lt;br /&gt;import org.simplemodeling.dsl.datatype._&lt;br /&gt;import org.simplemodeling.dsl.domain._&lt;br /&gt;import org.simplemodeling.dsl.domain.values._&lt;br /&gt;&lt;br /&gt;case class DEACustomer extends DomainActor {&lt;br /&gt;  term = "customer"&lt;br /&gt;  caption = "customer"&lt;br /&gt;  brief = &amp;lt;t&amp;gt;&amp;lt;/t&amp;gt;&lt;br /&gt;  description = &amp;lt;text&amp;gt;&amp;lt;/text&amp;gt;&lt;br /&gt;&lt;br /&gt;  id("customerId", DVICustomerId())&lt;br /&gt;  attribute("name", DVNCustomerName())&lt;br /&gt;  attribute("summary", XString)&lt;br /&gt;  attribute("phone", XString)&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;case class DVICustomerId extends DomainValueId {&lt;br /&gt;  term = "customerId"&lt;br /&gt;  caption = "customerId"&lt;br /&gt;  brief = &amp;lt;t&amp;gt;&amp;lt;/t&amp;gt;&lt;br /&gt;  description = &amp;lt;text&amp;gt;&amp;lt;/text&amp;gt;&lt;br /&gt;&lt;br /&gt;  attribute("value", XString)&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;case class DVNCustomerName extends DomainValueName {&lt;br /&gt;  term = "customerName"&lt;br /&gt;  caption = "customerName"&lt;br /&gt;  brief = &amp;lt;t&amp;gt;&amp;lt;/t&amp;gt;&lt;br /&gt;  description = &amp;lt;text&amp;gt;&amp;lt;/text&amp;gt;&lt;br /&gt;&lt;br /&gt;  attribute("value", XString)&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;デモでは、このモデルからg4上で動作するJavaソースコードを生成し、Androidアプリケーションとして動作させました。Javaソースコードの生成は、一部デモに間に合わなかったものもあったので、その後、少し改良しました。その改良版では、以下のソースコード(33ファイル、4.7Kステップ)を生成します。&lt;br /&gt;&lt;ul&gt;&lt;li&gt; BuyRestFeedAdapter.java&lt;br /&gt;&lt;/li&gt;&lt;li&gt; BuyRestFeedRepository.java&lt;br /&gt;&lt;/li&gt;&lt;li&gt; BuyRestViewActivity.java&lt;br /&gt;&lt;/li&gt;&lt;li&gt; CustomerRestFeedAdapter.java&lt;br /&gt;&lt;/li&gt;&lt;li&gt; CustomerRestFeedRepository.java&lt;br /&gt;&lt;/li&gt;&lt;li&gt; CustomerRestViewActivity.java&lt;br /&gt;&lt;/li&gt;&lt;li&gt; DDBuy.java&lt;br /&gt;&lt;/li&gt;&lt;li&gt; DDCustomer.java&lt;br /&gt;&lt;/li&gt;&lt;li&gt; DDGoods.java&lt;br /&gt;&lt;/li&gt;&lt;li&gt; DEACustomer.java&lt;br /&gt;&lt;/li&gt;&lt;li&gt; DEEBuy.java&lt;br /&gt;&lt;/li&gt;&lt;li&gt; DERGoods.java&lt;br /&gt;&lt;/li&gt;&lt;li&gt; DVIBuyId.java&lt;br /&gt;&lt;/li&gt;&lt;li&gt; DVICustomerId.java&lt;br /&gt;&lt;/li&gt;&lt;li&gt; DVIGoodsId.java&lt;br /&gt;&lt;/li&gt;&lt;li&gt; DVNCustomerName.java&lt;br /&gt;&lt;/li&gt;&lt;li&gt; DVNGoodsName.java&lt;br /&gt;&lt;/li&gt;&lt;li&gt; DemoAgent.java&lt;br /&gt;&lt;/li&gt;&lt;li&gt; DemoApplication.java&lt;br /&gt;&lt;/li&gt;&lt;li&gt; DemoContext.java&lt;br /&gt;&lt;/li&gt;&lt;li&gt; DemoContract.java&lt;br /&gt;&lt;/li&gt;&lt;li&gt; DemoController.java&lt;br /&gt;&lt;/li&gt;&lt;li&gt; DemoErrorModel.java&lt;br /&gt;&lt;/li&gt;&lt;li&gt; DemoFactory.java&lt;br /&gt;&lt;/li&gt;&lt;li&gt; DemoG3Driver.java&lt;br /&gt;&lt;/li&gt;&lt;li&gt; DemoModel.java&lt;br /&gt;&lt;/li&gt;&lt;li&gt; DemoModule.java&lt;br /&gt;&lt;/li&gt;&lt;li&gt; DemoProvider.java&lt;br /&gt;&lt;/li&gt;&lt;li&gt; DemoRepository.java&lt;br /&gt;&lt;/li&gt;&lt;li&gt; GoodsRestFeedAdapter.java&lt;br /&gt;&lt;/li&gt;&lt;li&gt; GoodsRestFeedRepository.java&lt;br /&gt;&lt;/li&gt;&lt;li&gt; GoodsRestViewActivity.java&lt;br /&gt;&lt;/li&gt;&lt;li&gt; IDemoRestDriver.java&lt;/li&gt;&lt;/ul&gt;このJavaプログラムをクラス図にすると以下のようになります。&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-p_IjPk9p5eM/Tl9aSvG5-LI/AAAAAAAAAMg/YBaf_2SXz3c/s1600/diagram.png" imageanchor="1"&gt;&lt;img border="0" height="234" src="http://1.bp.blogspot.com/-p_IjPk9p5eM/Tl9aSvG5-LI/AAAAAAAAAMg/YBaf_2SXz3c/s400/diagram.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;BuyRestViewActivity, CustomerRestViewActivity, GoodsRestViewActivityがAndroidの画面クラスであるActivity(Androidの画面クラス)です。これらのActivityがサーバー上に格納されているデータを画面に表示します。&lt;br /&gt;これらのActivityからDemoControllerを経由して、ドメインモデルを管理するクラスDemoModelにアクセスします。データの管理は、サーバーから取得したフィードデータをメモリ上に保持するクラスBuyRestFeedRepository, CustomerRestFeedRepository, GoodsRestFeedRepositoryで行い、これらのクラスをAndroidのウィジェットであるListView用のアダプタBuyRestFeedAdapter, CustomerRestFeedAdapter, GoodsRestFeedAdapterが使用します。&lt;br /&gt;また、サーバーとの通信はDemoG3Driverが行います。今回のデモではサーバー側はg3なので、g3と通信するためのドライバを使用していますが、ドライバはインタフェースIDemoRestDriverを実装していれば取り替え可能な構造になっています。&lt;br /&gt;クラス図の下に、Documentオブジェクト(DTO)であるDDCustomer, DDBuy, DDGoodsがありますが、これらのオブジェクトでデータのやりとりを行います。&lt;br /&gt;クラス図のざっくりとした説明は以上の通りです。追々詳細な情報を書いていく予定です。&lt;br /&gt;ここで強調したいのは、(トイプログラムではなくて)ある程度本格的なアプリケーションを作成する場合、ごく小さなドメインモデルからでも、これらのクラス群を作成しなければならないということです。一般的なJavaプログラムでも必要なものもありますし、Android特有のクラスもありますが、いずれにしても相当量のコーディングが必要になります。しかも、これらのクラス群はドメインモデルが決まれば、Android上でどう実装するのかというのも、ほとんど決まってしまうので、人力でコーディングするのは、かなりもったいない作業です。こういった定型部分を自動コーディングしてしまうことがSimpleModelerの目的です。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7964484936470829118-460609499568054326?l=modegramming.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://modegramming.blogspot.com/feeds/460609499568054326/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://modegramming.blogspot.com/2011/09/simpldemodelerandroid.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/460609499568054326'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/460609499568054326'/><link rel='alternate' type='text/html' href='http://modegramming.blogspot.com/2011/09/simpldemodelerandroid.html' title='SimpldeModelerが生成するAndroidコード'/><author><name>asami</name><uri>http://www.blogger.com/profile/12083671403528595185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_4HtJQwbXqEY/S4sSwhKz5fI/AAAAAAAAAFs/IvXW6ca5RGE/S220/profile.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-p_IjPk9p5eM/Tl9aSvG5-LI/AAAAAAAAAMg/YBaf_2SXz3c/s72-c/diagram.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7964484936470829118.post-37139408814492122</id><published>2011-08-31T09:00:00.002+09:00</published><updated>2011-08-31T09:00:04.037+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='F#'/><title type='text'>F#考 - クラウド温泉2.0@小樽</title><content type='html'>8月27,28日に&lt;a href="http://www.facebook.com/home.php?sk=group_225282024151633"&gt;クラウド温泉@小樽&lt;/a&gt;が開催されました。今回のクラウド温泉も盛りだくさんの内容で、ボクとしてはF#について詳しいお話を聞けたのが収穫でした。発表者の@bleisさん、MSの荒井さん、参加者の皆様、どうもありがとうございました。&lt;br /&gt;&lt;br /&gt;F#はScalaと同じオブジェクト指向と関数型のハイブリッド言語で、ざっくりとはだいたい同じことができると捉えてみてよさそうです。ただし、言語の狙いは異なるので、利用シーンは違ってきます。&lt;br /&gt;&lt;br /&gt;以下、F#の知識は当日の聞きかじりを元にしているので、不正確なところが多いと思いますが、ボクの現時点での認識のメモということでご了承ください。&lt;br /&gt;&lt;br /&gt;F#の言語のセマンティクスは関数型が主でオブジェクト指向は従のようです。&lt;br /&gt;&lt;br /&gt;関数型の世界で扱うデータはレコード/タプルで、構造体的な言語要素となっています。そして、このレコードとは別にクラス/オブジェクトが用意されています。(変数に関数をバインドしてメソッド的に使えるかもしれませんが、この点は未確認。)&lt;br /&gt;つまりデータを記述する言語要素が二系統あって、そのうちの一系統を使うと関数型言語らしいプログラミングが堪能できるということですね。&lt;br /&gt;&lt;br /&gt;一方、クラス/オブジェクトは、当日確認しなかったのですが、恐らく.NETのクラス/オブジェクトだろうと思います。クラス/オブジェクトを通じて.NETのクラス/オブジェクトをC#やVBと相互に連携できるのではないかと推測します。&lt;br /&gt;&lt;br /&gt;データを記述する言語要素が二系統あるのは、関数型言語としての純粋性を保ちたかったということもあるでしょうし、.NETのクラス/オブジェクトを関数型言語向けに拡張するのが難しかった、という制約に起因するところもありそうです。&lt;br /&gt;&lt;br /&gt;また、データは基本的にイミュータブルで、mutableというキーワードを付けるとミュータブルにもできるというアプローチになっています。この点からも関数型の方に軸足があることが分かります。このため、状態の存在を前提としたプログラミングには、あまり向いておらず、つまるところオブジェクト指向プログラミング言語としてはあまり快適ではなさそうです。&lt;br /&gt;&lt;br /&gt;F#では、型パラメータの省略ができて簡潔な記述が可能になっていますが、関数をオブジェクトのメソッドとしてポリモーフィックに動かすことをやめることにより(クラス/オブジェクトではなくレコード/タプルを使う効果)、共変/反変まわりの指定を考えなくてもよいので、そのあたりが寄与しているのかなと感じました。これも、関数型側に軸足を持っている効果です。&lt;br /&gt;&lt;br /&gt;以上のようにF#は関数型側に大きく機能を倒して、オブジェクト指向的にはほどほどにして、関数型言語の美点を伸ばしていくアプローチのようです。&lt;br /&gt;&lt;br /&gt;このアプローチの延長線上で、コンピューテーション式、seq/yieldといったところが、関数型言語の高度な応用で、マニア的に面白いところですね。どちらもDSLの記述力を高めることに大きく寄与する機能です。&lt;br /&gt;&lt;br /&gt;F#は関数型言語として素晴らしい言語であるのは確かですが、関数型側に機能を倒しているため、オブジェクト指向言語としては快適というわけではなく、実務へ適用する汎用言語としては考えにくいのかなという印象を持ちました。F#一本ですべての応用を記述する、ということにはならないかなと。&lt;br /&gt;&lt;br /&gt;そこで、F#を取り囲む文脈を考えてみましょう。F#は.NET上で動作することを前提とした言語であり、C#やC++といった.NETの他の言語と共存することが前提です。&lt;br /&gt;&lt;br /&gt;C#の場合は、VBなどを置き換えていって、.NETの中心言語にしていくという意図もあったかと思いますが、F#の場合は、C#を置き換えるといったことは意図しておらず、C#を補完する立場になるでしょう。そうすると、C#ができることを全部カバーした上で、新たに関数型の機能を追加するといったことをする必要はなく、オブジェクト指向的な文法は.NETのクラス/オブジェクトと連携できるものがあれば十分と割り切ることができます。その上で、C#ではできない関数型のプログラミングモデルを使いやすいものにする方向に力をそそいでいるわけですね。&lt;br /&gt;&lt;br /&gt;そういう意味で、F#は.NETワールドを構成するパーツの一つとして、並列プログラミングやDSLといった関数型に適した分野をカバーする専用言語という戦略上の意図を持った言語であると推測されます。&lt;br /&gt;今後の技術の発展の方向は並列プログラミングとDSLが二大潮流になることは確実なので、この2つの分野に強い関数型言語を並行プログラミングとDSL向けを意識してチューニングし、.NETワールド内でのポジションを明確にした上で提供してきているのにはMicrosoftの底力を感じました。&lt;br /&gt;&lt;br /&gt;F#は、monoと組合わせてMacやLinuxでも普通に動くみたいなので、DSLにフォーカスした応用ではプラットフォームを問わず実用的に使用できそうです。そういう意味でも面白い存在です。&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7964484936470829118-37139408814492122?l=modegramming.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://modegramming.blogspot.com/feeds/37139408814492122/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://modegramming.blogspot.com/2011/08/f-20.html#comment-form' title='1 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/37139408814492122'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/37139408814492122'/><link rel='alternate' type='text/html' href='http://modegramming.blogspot.com/2011/08/f-20.html' title='F#考 - クラウド温泉2.0@小樽'/><author><name>asami</name><uri>http://www.blogger.com/profile/12083671403528595185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_4HtJQwbXqEY/S4sSwhKz5fI/AAAAAAAAAFs/IvXW6ca5RGE/S220/profile.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7964484936470829118.post-6207233308364159001</id><published>2011-07-19T09:00:00.001+09:00</published><updated>2011-07-19T09:00:04.609+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='simplemodeler'/><category scheme='http://www.blogger.com/atom/ns#' term='g3'/><category scheme='http://www.blogger.com/atom/ns#' term='g4'/><title type='text'>SimpleModeler (クラウド温泉@小樽)</title><content type='html'>&lt;a href="http://atnd.org/events/17520"&gt;クラウド温泉＠小樽&lt;/a&gt;では、モデルコンパイラSimpleModelerからg3フレームワーク上で動作するクラウドサービス、g4フレームワーク上で動作するAndroidクライアントを自動生成し、Androidクライアントとクラウドサービスが連携動作するデモを行う予定です。&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-Va32_JVBdGY/TiTBCncUlXI/AAAAAAAAAMQ/z5OlJoMJVes/s1600/g3g4demo.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="400" src="http://2.bp.blogspot.com/-Va32_JVBdGY/TiTBCncUlXI/AAAAAAAAAMQ/z5OlJoMJVes/s400/g3g4demo.png" width="353" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;まずScala DSLでモデルを記述します。(デモではより効果を狙ってCSVでモデル記述するかもしれません。)&lt;br /&gt;このScala DSLからSimpleModelerを使って、Android用クライアントとGoogle App Engine/Tomcat(Glassfish)の両方で動作するRESTサービスを生成します。&lt;br /&gt;生成された、AndroidクライアントとRESTサービスは連携して、データに対するCRUD処理を行うことができます。&lt;br /&gt;&lt;br /&gt;Android用クライアントは&lt;a href="http://modegramming.blogspot.com/2011/07/g4.html"&gt;g4フレームワーク&lt;/a&gt;上で動作します。g4フレームワークはGoogle GuiceによるDIをベースにしたAndroidアプリケーションフレームワークです。&lt;br /&gt;&lt;br /&gt;サーバープログラムは&lt;a href="http://modegramming.blogspot.com/2011/07/g3.html"&gt;g3フレームワーク&lt;/a&gt;上で動作します。g3フレームワークはGoogle App Engineと、TomcatやGlassfishなどの通常のServletコンテナ上で動作します。ServletコンテナはEC2を始め、一般的なクラウドプラットフォーム上で動作します。このため、g3フレームワークを用いることでクラウドプラットフォーム上で可搬性のあるアプリケーションを作成することができます。&lt;br /&gt;&lt;h4&gt;&lt;a href="http://www.blogger.com/post-create.g?blogID=7964484936470829118" name="doc1_id19"&gt;デモの目的&lt;/a&gt;&lt;br /&gt;&lt;/h4&gt;デモでは、見栄えや分りやすさの点からプログラミングレスで自動生成したアプリケーションがそのまま動作することを主眼とします。&lt;br /&gt;しかし、このデモはモデル駆動開発でアプリケーションプログラムが自動生成されるということを主張するのが趣旨ではありません。現在の所、CRUDのような特定の定形処理以外はアプリケーションの自動生成は、まだまだ実用化には程遠いからです。&lt;br /&gt;&lt;br /&gt;それでは、SimpleModelerによるプログラムの自動生成は何をコンセプトとしているのでしょう。&lt;br /&gt;それは、ひとことで言うと「ドメインライブラリの自動コーディング」です。&lt;br /&gt;&lt;h4&gt;&lt;a href="http://www.blogger.com/post-create.g?blogID=7964484936470829118" name="doc1_id22"&gt;ドメインモデル&lt;/a&gt;&lt;br /&gt;&lt;/h4&gt;オブジェクトモデリングでは大きく分析モデル(またはPIM, Platform Indenpendent Model)と設計モデル(またはPSM, Platform Specific Model)の2つのモデルを作成します。これはモデルの抽象度が分類の軸になっています。&lt;br /&gt;分析モデルに対して、動作ターゲットのプラットフォームと非機能要求を加えて、実際に動作するプログラムの設計図となる設計モデルとなります。&lt;br /&gt;&lt;br /&gt;モデルの分類の軸は他にも色々ありますが、筆者が有効と考えているものにアプリケーションモデルとドメインモデルの軸があります。&lt;br /&gt;ドメインモデルは、アプリケーションの問題領域の構造をモデル化したものです。主に静的モデルにフォーカスしたモデルで、静的構造中心、モデルのライフサイクルが長い、自動生成の対象になりやすいという特性があります。&lt;br /&gt;一方、アプリケーションモデルはドメインモデルを使用して、アプリケーション利用者の目的を達成するための仕組みをモデル化したものです。主に動的モデルにフォーカスしたモデルで、アプリケーションモデルは、振舞い中心、モデルのライフサイクルが短い、自動生成の対象になりにくいという特性があります。&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-HCsX9tw7qww/TiTBHve6UDI/AAAAAAAAAMU/k885C7uO1nc/s1600/LibraryAutoCoding.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="217" src="http://4.bp.blogspot.com/-HCsX9tw7qww/TiTBHve6UDI/AAAAAAAAAMU/k885C7uO1nc/s400/LibraryAutoCoding.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;ドメインモデルは、静的構造(クラス図)中心となりますが、動的モデルとして状態機械、ルールモデル、アクション言語を併用します。(アプリケーションモデルでは、ユースケース、インタラクション、コラボレーションなどを使用します。)&lt;br /&gt;&lt;br /&gt;静的構造図が中心のモデルの場合、オブジェクト指向言語を使うと設計モデルとプログラムのセマンティクスギャップが非常に少ないので、設計モデルを飛ばして直接プログラミングすることも可能です。短期開発では、その方が効率もよく、プログラムの品質もよくなるでしょう。また、持続性を重視する製品開発でも、静的構造のみでよければER図などのデータモデリングで十分です。&lt;br /&gt;一方、状態機械やルールモデルなど、プログラミング言語とのセマンティクスギャップが大きいモデルを使用する場合は短期開発であっても引き続き設計モデルが有効です。&lt;br /&gt;&lt;h4&gt;&lt;a href="http://www.blogger.com/post-create.g?blogID=7964484936470829118" name="doc1_id25"&gt;ドメインライブラリ&lt;/a&gt;&lt;br /&gt;&lt;/h4&gt;現状では、ドメインモデルを作成しても手作業でプログラミングすることが多く、モデルを作成しても作業量は減りません。プログラミング側での改修がモデルに反映されなくなり、長期的にはモデルが死んでしまうという問題もあります。&lt;br /&gt;&lt;br /&gt;ドメインモデルからRDBMSのDDLや、O/Rマッパーのコード生成などを行うツールはあるので、データモデリングの範囲では自動生成を取り込んだ運用を行うことは可能です。&lt;br /&gt;しかし、動的モデルを包含したオブジェクトモデル全体のスコープでは、ドメインモデルに限定しても、プログラムの自動生成はまだまだ発展途上といえるでしょう。&lt;br /&gt;しかし、ドメインモデルを実用的に記述できる範囲でドメインモデルのプロファイルを定めておくことは可能です。筆者はこの目的でドメインモデル(とアプリケーションモデル)のプロファイルをまとめています。詳しくはこちらをどうぞ。(『&lt;a href="http://www.amazon.co.jp/dp/4822283666"&gt;上流工程UMLモデリング&lt;/a&gt;』、『&lt;a href="http://www.amazon.co.jp/dp/479811748X"&gt;マインドマップではじめるモデリング講座&lt;/a&gt;』)&lt;br /&gt;&lt;br /&gt;ドメインモデルの重要な特性の一つは、自動生成に適しているということです。決められたパーツを使ってドメインモデルを記述するという運用にすれば、分析モデルから、設計モデルをバイパスしてほぼ完全に実装を自動生成することができます。また設計モデルも仕様書という形で生成可能です。もちろん、100%完全は難しいでしょうが、適切な拡張ポイントを生成することで、部分的なプログラミングで補完可能にできるでしょう。&lt;br /&gt;&lt;br /&gt;SimpleModelerは、この実現を目指しています。&lt;br /&gt;&lt;h4&gt;&lt;a href="http://www.blogger.com/post-create.g?blogID=7964484936470829118" name="doc1_id34"&gt;ドメインライブラリとアプリケーションフレームワーク&lt;/a&gt;&lt;br /&gt;&lt;/h4&gt;ドメインライブラリを単体で生成するのも十分に有効ですが、適切なアプリケーションフレームワークがあれば、この枠組みの中に組み込んでしまえば、アプリケーション開発をより効率的に行うことができます。&lt;br /&gt;アプリケーションフレームワークの上にドメインライブラリをビルトインしたものを土台にしてアプリケーション開発を進めることができます。&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-mYAKwxo_Pcc/TiTBAqykwsI/AAAAAAAAAMM/lPAaEgnfjz0/s1600/DomainLibraryArch.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="169" src="http://2.bp.blogspot.com/-mYAKwxo_Pcc/TiTBAqykwsI/AAAAAAAAAMM/lPAaEgnfjz0/s200/DomainLibraryArch.png" width="200" /&gt;&lt;/a&gt;&lt;/div&gt;クラウドアプリケーション向けにg3フレームワーク、Androidアプリケーション向けにg4フレームワークを開発したので、これらのフレームワーク上にビルトインできるドメインライブラリを生成します。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;h4&gt;&lt;a href="http://www.blogger.com/post-create.g?blogID=7964484936470829118" name="doc1_id37"&gt;自動コーディング&lt;/a&gt;&lt;br /&gt;&lt;/h4&gt;モデル駆動開発について以下のような疑問をしばしば耳にします。&lt;br /&gt;&lt;ul&gt;&lt;li&gt; モデルからプログラム全体を生成するのは無理ではないか。&lt;br /&gt;&lt;/li&gt;&lt;li&gt; モデルから自動生成したプログラムを直接修正した時に、モデルに反映できないと、以降の開発にモデルを使うことができない。&lt;br /&gt;&lt;/li&gt;&lt;li&gt; モデルレベルでデバッグできないとバグ修正ができない。&lt;/li&gt;&lt;/ul&gt;つまりモデル駆動に対してプログラミング言語のコンパイラ的な運用を期待しているわけです。これは一つの理想ではあるのですが、現段階の技術レベルでは難しく、ここに判断基準を置いてしまうと、自動生成は時期尚早という判断になってしまいます。&lt;br /&gt;しかし、ドメインモデルに範囲を限定すれば、相当量のコードの自動生成が可能なので、これをまったく無視するのはあまりにももったいない。&lt;br /&gt;そこで、コンパイラモデルに代わって、プログラムの自動生成をソフトウェア開発の枠組に取り込む切り口として考えているのが『クラスライブラリの「自動コーディング」』というコンセプトです。&lt;br /&gt;&lt;br /&gt;言うまでもなくソフトウェア開発では、多数のクラスライブラリを併用して開発を進めるのが普通です。多くのクラスライブラリはオープンソースであり、APIリファレンスとソースコードの両方を参照して利用できます。&lt;br /&gt;基本的にはAPI仕様をみて使いますが、詳細仕様を知りたい時にはソースコードも参照します。デバッグ時にはクラスライブラリのソースも取り込んでブレークポイントを張ったり、変数の値を確認したりします。&lt;br /&gt;クラスライブラリのバグ修正は追加は、短期対応と長期対応の2つのフェーズで行われます。まず、短期対応として、必要に応じてパッチを当てたりして修正します。&lt;br /&gt;その後、バグの修正や機能追加は所定の手続きをへてクラスライブラリに反映されます。長期対応として、この修正が取り込まれた新しいバージョンのクラスライブラリを、改めてアプリケーションに取り込みます。&lt;br /&gt;&lt;br /&gt;ここで、発想を少し変えてみましょう。&lt;br /&gt;事前に誰かが用意したクラスライブラリでも、プログラムが自動生成したクラスライブラリでも、利用者からは全く同じです。&lt;br /&gt;つまり、クラスライブラリとしてとして運用するのであれば、プログラムの自動生成を用いても、今までの開発と何ら変わるところはないはずです。&lt;br /&gt;&lt;br /&gt;次は、ニーズの面から考えてみましょう。&lt;br /&gt;プログラミングをするときに、特定のドメイン向けのクラスライブラリが整備されているととても効率的です。&lt;br /&gt;しかし、特定のドメイン向けのドメインクラスライブラリは、よほど共通して使用される大きなドメインでないと事前に誰かが用意しているということはありません。&lt;br /&gt;このため、ソフトウェア開発の初期段階では、ドメインモデルをコードとして実装する作業を黙々と続けることになります。あるいは、画面とデータベースをつなぐ処理として、画面のイベントハンドラーの中にドメイン処理が重複して繰り返し生産されることになります。&lt;br /&gt;前者では、ドメインモデルのコーディングが開発全体のボトルネックになりますし、後者では、アプリケーションの保守性、拡張性に問題が出てきます。&lt;br /&gt;この問題を、ドメインクラスライブラリの自動コーディングが解決することができます。前述したようにドメインモデルはほぼ完全な自動生成が可能なので、ドメインライブラリを自動生成するのは実用範囲です。そこで、ドメインモデルをドメインクラスライブラリとして"自動コーディング"してしまおう、というわけです。&lt;br /&gt;出来合いの標準品ではなく、自分向けのクラスライブラリですから、アプリケーションのニーズにもぴったり合います。使い方は、ソースコードが提供されている通常のクラスライブラリと全く同じです。&lt;br /&gt;&lt;h4&gt;&lt;a href="http://www.blogger.com/post-create.g?blogID=7964484936470829118" name="doc1_id52"&gt;クラウド温泉＠小樽&lt;/a&gt; &lt;/h4&gt;SimpleModelerのコンセプトが「ドメインライブラリの自動コーディング」であることを説明しました。クラウド温泉＠小樽では、SimpleModelerのデモをネタに、ドメインライブラリの自動コーディングというコンセプト、実現性、応用について議論できればと思っています。&lt;br /&gt;また、クラウドアプリケーション、スマートデバイスによって、ドメインモデリングの技術にも色々な影響があることが予想されます。このあたりも面白い議論ができそうです。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7964484936470829118-6207233308364159001?l=modegramming.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://modegramming.blogspot.com/feeds/6207233308364159001/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://modegramming.blogspot.com/2011/07/simplemodeler.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/6207233308364159001'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/6207233308364159001'/><link rel='alternate' type='text/html' href='http://modegramming.blogspot.com/2011/07/simplemodeler.html' title='SimpleModeler (クラウド温泉@小樽)'/><author><name>asami</name><uri>http://www.blogger.com/profile/12083671403528595185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_4HtJQwbXqEY/S4sSwhKz5fI/AAAAAAAAAFs/IvXW6ca5RGE/S220/profile.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-Va32_JVBdGY/TiTBCncUlXI/AAAAAAAAAMQ/z5OlJoMJVes/s72-c/g3g4demo.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7964484936470829118.post-66638027078687347</id><published>2011-07-11T07:30:00.002+09:00</published><updated>2011-07-11T07:30:00.448+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='g4'/><title type='text'>g4 (クラウド温泉＠小樽)</title><content type='html'>クラウド温泉@小樽では、Androidアプリケーションの自動生成のデモをしますが、その基盤となるAndroidアプリケーションフレームワークであるg4について説明します。&lt;br /&gt;&lt;br /&gt;g4はSImpleModelerによるAndroidアプリケーション自動生成の基盤として新規作成したアプリケーションフレームワークです。&lt;br /&gt;&lt;br /&gt;g4の基本構成は以下の通りです。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-fxr8VpbC6Zg/ThoYCvRfBEI/AAAAAAAAAMI/i-jvHepsYic/s1600/AndroidClassLibrary.png" imageanchor="1"&gt;&lt;img border="0" height="367" src="http://2.bp.blogspot.com/-fxr8VpbC6Zg/ThoYCvRfBEI/AAAAAAAAAMI/i-jvHepsYic/s400/AndroidClassLibrary.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;ボクのAndroid開発経験から、Androidのアプリケーションアーキテクチャとして、この図に示したものがよいのではないかという仮説のものと、このアーキテクチャの基盤となるクラス群を提供してます。&lt;br /&gt;&lt;br /&gt;アーキテクチャの基盤となるクラスは以下の3つに分類できます。&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt; Android基本ライブラリを拡張&lt;br /&gt;&lt;/li&gt;&lt;li&gt; Google Guideを拡張&lt;br /&gt;&lt;/li&gt;&lt;li&gt; g4独自クラス&lt;/li&gt;&lt;/ul&gt;&lt;h4&gt;&lt;a href="http://www.blogger.com/post-edit.g?blogID=7964484936470829118&amp;amp;postID=66638027078687347" name="doc1_id25"&gt;Android基本ライブラリ&lt;/a&gt; &lt;/h4&gt;Android基本ライブラリが提供するクラスです。これらのクラスをさらに拡張した基底クラスを用意しています。&lt;br /&gt;&lt;dl&gt;&lt;dt&gt;&lt;br /&gt;Application&lt;br /&gt;&lt;/dt&gt;&lt;dd&gt;アプリケーション&lt;/dd&gt;&lt;dt&gt;&lt;br /&gt;Activity&lt;br /&gt;&lt;/dt&gt;&lt;dd&gt;Android画面&lt;/dd&gt;&lt;dt&gt;&lt;br /&gt;Fragment&lt;br /&gt;&lt;/dt&gt;&lt;dd&gt;Android画面の断片(Android 3.0以降)&lt;/dd&gt;&lt;dt&gt;&lt;br /&gt;View&lt;br /&gt;&lt;/dt&gt;&lt;dd&gt;Android画面の部品&lt;/dd&gt;&lt;dt&gt;&lt;br /&gt;Service&lt;br /&gt;&lt;/dt&gt;&lt;dd&gt;アプリケーション本体を補完するサービス&lt;/dd&gt;&lt;dt&gt;&lt;br /&gt;Intent&lt;br /&gt;&lt;/dt&gt;&lt;dd&gt;Activity/Service間で流通する情報&lt;/dd&gt;&lt;dt&gt;&lt;br /&gt;ContentProvider&lt;br /&gt;&lt;/dt&gt;&lt;dd&gt;情報提供&lt;/dd&gt;&lt;/dl&gt;Activity, Fragment, ViewはCRUDなど特定のユースケース向けのソースコード自動生成が行われるので、それに対応した拡張を行っています。&lt;br /&gt;Service, Intent, ContentProviderは、ソースコードの自動生成の直接の対象です。特にドメインモデルからIntentとContentProviderはほぼ完全な形で自動生成できる見込みです。&lt;br /&gt;Serviceは、ファサード部分を自動生成して、実現部分をコーディングする形になりますが、これに対応した拡張を行う予定です。&lt;br /&gt;&lt;h4&gt;&lt;a href="http://www.blogger.com/post-edit.g?blogID=7964484936470829118&amp;amp;postID=66638027078687347" name="doc1_id73"&gt;Google Guiceを拡張&lt;/a&gt; &lt;/h4&gt;g4は、DI(Dependency Injection)を用いたアプリケーション組立てをサポートします。DI機能にはGoogle Guice(without AOP)を用いています。&lt;br /&gt;Guiceを使ったDIで、アプリケーションを構築する各オブジェクトの結合度を低くし、オブジェクトの再利用性、拡張性、保守性、テスタビリティを高めます。&lt;br /&gt;このGuiceのモジュールを定義するクラスがModuleです。g4ではGuiceのMiduleをg4用に拡張した基底クラスを提供しています。&lt;br /&gt;&lt;dl&gt;&lt;dt&gt;&lt;br /&gt;Module&lt;br /&gt;&lt;/dt&gt;&lt;dd&gt;Google Guiceのモジュール定義クラス&lt;/dd&gt;&lt;/dl&gt;&lt;h4&gt;&lt;a href="http://www.blogger.com/post-edit.g?blogID=7964484936470829118&amp;amp;postID=66638027078687347" name="doc1_id85"&gt;g4クラス&lt;/a&gt; &lt;/h4&gt;g4では以下のAndroidが提供する基本クラスに、以下のクラスを追加してAndroidアプリケーションのアプリケーションアーキテクチャを構築しています。&lt;br /&gt;&lt;dl&gt;&lt;dt&gt;&lt;br /&gt;Controller&lt;br /&gt;&lt;/dt&gt;&lt;dd&gt;画面が実行する責務を提供&lt;/dd&gt;&lt;dt&gt;&lt;br /&gt;Agent&lt;br /&gt;&lt;/dt&gt;&lt;dd&gt;モデルの更新を伴う責務を実装&lt;/dd&gt;&lt;dt&gt;&lt;br /&gt;Model&lt;br /&gt;&lt;/dt&gt;&lt;dd&gt;ドメインモデル&lt;/dd&gt;&lt;dt&gt;&lt;br /&gt;ErrorModel&lt;br /&gt;&lt;/dt&gt;&lt;dd&gt;エラーモデル&lt;/dd&gt;&lt;dt&gt;&lt;br /&gt;Driver&lt;br /&gt;&lt;/dt&gt;&lt;dd&gt;外部リソースにアクセスするドライバ&lt;/dd&gt;&lt;dt&gt;&lt;br /&gt;Factory&lt;br /&gt;&lt;/dt&gt;&lt;dd&gt;オブジェクトの生成とインジェクション&lt;/dd&gt;&lt;dt&gt;&lt;br /&gt;Repository&lt;br /&gt;&lt;/dt&gt;&lt;dd&gt;エンティティオブジェクトの管理&lt;/dd&gt;&lt;/dl&gt;Androidでは、画面のインタラクションをActivityが遂行しますが、シンプルな造りの場合、すべての責務をActivity内に実装することになります。&lt;br /&gt;この方法は初期実装は楽ですが、プログラムがある程度大きくなってくると、再利用性、拡張性、保守性、テスタビリティが損なわれることになります。&lt;br /&gt;そこで、持続的に機能拡張を続ける本格的なアプリケーションの場合はきちんとしたアプリケーションアーキテクチャの構成を取るのが得策です。アプリケーションアーキテクチャでは、分散対象となる部品の構成、分散配置の戦略を定めます。そしてユースケースを構成する各種責務を色々なオブジェクトに分散配置していくことになります。&lt;br /&gt;g4では、以下の方針で責務の分散配置を行います。&lt;br /&gt;&lt;ul&gt;&lt;li&gt; 利用者視点でドメインモデルを操作する責務はControllerに配置&lt;br /&gt;&lt;/li&gt;&lt;li&gt; ドメインモデル視点でモデルの更新処理を行う責務はAgentに配置&lt;br /&gt;&lt;/li&gt;&lt;li&gt; ドメインモデルはModelに配置&lt;br /&gt;&lt;/li&gt;&lt;li&gt; エラー処理の責務はErrorModelに集約&lt;br /&gt;&lt;/li&gt;&lt;li&gt; 外部リソースへのアクセスはDriverに集約&lt;/li&gt;&lt;/ul&gt;また、ドメインモデル操作の基本機能であるFactoryとRepositoryも用意しています。&lt;br /&gt;Androidの基本ライブラリのみだと、ここで述べたアプリケーションアーキテクチャを実装することが難しいので、必要なオブジェクトをg4独自クラスとして追加しているわけです。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7964484936470829118-66638027078687347?l=modegramming.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://modegramming.blogspot.com/feeds/66638027078687347/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://modegramming.blogspot.com/2011/07/g4.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/66638027078687347'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/66638027078687347'/><link rel='alternate' type='text/html' href='http://modegramming.blogspot.com/2011/07/g4.html' title='g4 (クラウド温泉＠小樽)'/><author><name>asami</name><uri>http://www.blogger.com/profile/12083671403528595185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_4HtJQwbXqEY/S4sSwhKz5fI/AAAAAAAAAFs/IvXW6ca5RGE/S220/profile.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-fxr8VpbC6Zg/ThoYCvRfBEI/AAAAAAAAAMI/i-jvHepsYic/s72-c/AndroidClassLibrary.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7964484936470829118.post-1208802792275023857</id><published>2011-07-09T17:02:00.001+09:00</published><updated>2011-07-11T06:32:20.793+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='g3'/><title type='text'>g3 (クラウド温泉@小樽)</title><content type='html'>8月27日(土)/28日(日)に開催される&lt;a href="http://www.facebook.com/home.php?sk=group_225282024151633"&gt;クラウド温泉@小樽&lt;/a&gt;に向けて、現時点でのg3/g4/SimpleModelerの技術について整理しておこうと思います。&lt;br /&gt;&lt;br /&gt;Scala DSLベースのモデルコンパイラSimpleModelerでは、当初Glassfish(Java EE)、Spring、Google App Engineといったクラウドプラットフォームあるいはその上で利用するフレームワークのAPI上に直接プログラムを生成することを目指していました。&lt;br /&gt;&lt;br /&gt;実際に、Google App Engineでのプログラム生成を実装したところ、生成するプログラム側で相当な作り込みが必要となり、ある意味フレームワークそのものを生成するような形になってしまうことが分かりました。結局、共通部品として必要なものは、自動生成ではなくフレームワークとして独立して提供するのが筋ということですね。&lt;br /&gt;&lt;br /&gt;クラウドアプリケーション向けのフレームワークとしては、既存のフレームワークを流用するのが有力な選択肢です。Java EEやSpringといったエンタープライズ向けのWebフレームワーク、あるいはMule ESBやCamelといったESBについても比較検討したのですが、ボクが必要としている機能とはまだま距離があるということで、新規に開発することにしました。&lt;br /&gt;&lt;br /&gt;こうして開発したのがg3フレームワークです。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;&lt;a href="" name="doc1_id16"&gt;目標&lt;/a&gt;&lt;br /&gt;&lt;/h2&gt;g3を一言で表現すると『Scala DSLベースREST指向粗粒度非同期コンポーネントフレームワーク』です。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt; フレームワークのアプリケーションインタフェースにはScala DSLを用いる。&lt;br /&gt;&lt;/li&gt;&lt;li&gt; 粗粒度のコンポーネントを非同期で連携してアプリケーションを構築する。&lt;br /&gt;&lt;/li&gt;&lt;li&gt; コンポーネント間の連携にはRESTを用いる。&lt;/li&gt;&lt;/ul&gt;開発時に念頭においていたのはEIP(Enterprise Integration Patterns)です。EIPによって非同期コンポーネントをAtomPubのフィードメッセージで連携するアーキテクチャがクラウドアプリケーションの一つの形ではないかというのが基本アイデアになっています。 &lt;br /&gt;&lt;h2&gt;&lt;a href="" name="doc1_id31"&gt;プログラミングモデルとDSL&lt;/a&gt; &lt;/h2&gt;クラウドアプリケーションのアプリケーションアーキテクチャとしてどのようなものが適切かというのはまだまだ未知の領域ですが、ボクが仮説として考えているのが並行動作する粗粒度コンポーネントをメッセージングで接続する、コンポーネントベースのアーキテクチャです。 粗粒度コンポーネント間の連携プロトコルとしてRESTセマンティクスを用いることで、プログラミングモデル上、インターネット空間とシームレスに接続することができます。 &lt;br /&gt;&lt;h3&gt;&lt;a href="" name="doc1_id33"&gt;Scala DSL&lt;/a&gt; &lt;/h3&gt;このアーキテクチャを取るときの論点の一つが、コンポーネントの組立てをいかに簡単に記述するのかという点です。このようなコンポーネントの組立てにXMLを用いるのが従来の手法ですが、以下の問題があります。まず、XMLによる定義は記述が煩雑になってしまうこと。また、プログラミング言語とのシームレスな連携ができないので、プログラミング言語とXMLの二本立ての管理になってしまうという問題もあります。関連して、定義ファイルにプログラミング的な技法、たとえばマクロを導入して定義の共通部をまとめることにできるようにする、いったことを実現することも困難です。 この問題を解決するために採用したのが、Scalaをホスト言語にしたDSLです。専用言語であるDSLを用いることで、メッセージングによるコンポーネントの連携を簡潔に記述することができます。 また、Scalaを通してScalaだけでなくJavaやその他JavaVM上で動作するプログラミング言語で記述されたプログラムと連携することができます。 &lt;br /&gt;&lt;h3&gt;&lt;a href="" name="doc1_id36"&gt;REST指向&lt;/a&gt; &lt;/h3&gt;REST指向は、Webプロトコルとのシームレスな連携、フレーム内リソース識別のURI化、コンポーネント連携に用いるメッセージをAtomフィードベースにしていることにより実現しています。 &lt;br /&gt;&lt;h3&gt;&lt;a href="" name="doc1_id39"&gt;イベント駆動&lt;/a&gt; &lt;/h3&gt;クラウドアプリケーションは非同期に発生するイベントを受けて動作するイベント駆動で処理する構造がアプリケーションの基本アーキテクチャになるというのがボクの仮説の一つです。 比喩的には、割り込みハンドラーとシステムアクティビティでアプリケーションを構築する組込み機器のような構造をイメージしています。 イベント駆動はまだ実現できていませんが、その前提となるメッセージの到着を起点に処理を駆動するメカニズムは実現しています。エンティティとして永続管理するビジネスイベントと、揮発性のシステムイベントをどのように再構成して、フレームワークのアーキテクチャ上に位置付けていくのか考慮中です。 &lt;br /&gt;&lt;h3&gt;&lt;a href="" name="doc1_id42"&gt;状態機械&lt;/a&gt; &lt;/h3&gt;イベントの発生を受けて、発生したイベントとリソースの状態の組に対して、適合するアクションを実行するというのが、オブジェクト指向の動的モデルの基本的な考えです。 イベント駆動型のアプリケーションでは、この状態機械による動的モデルの記述と実行が重要な意味を持ってくることになります。残念ながら現状のオブジェクト指向言語では、状態機械のサポートを行っていないのでプログラムで直接記述することができません。 このメカニズムをフレームワークで実現したいというのもg3の目的の一つです。 プログラミング言語でサポートされていない必須機能をフレームワークで実現するわけですが、Scala DSLによるアプリケーションインタフェースを用いるので、ある意味新しい専用言語を導入するのと同じインパクトがあります。 状態機械の記述方式と上流モデルとの連携方法について、前述のイベント駆動のメカニズム、記述方法と合わせて検討中です。 &lt;br /&gt;&lt;h3&gt;&lt;a href="" name="doc1_id45"&gt;スケーラビリティ&lt;/a&gt; &lt;/h3&gt;クラウドアプリケーションでは、スケーラビリティも重要な要件です。すべてのアプリケーションがフルにスケーラビリティを追求する必要はありませんが、必要に応じてスケーラビリティを確保する手段をモデリング、アプリケーションアーキテクチャ、フレームワークといった様々な層の技術の中に事前に織り込んでおく必要があります。 g3はスケーラビリティ確保の手段として非同期メッセージング、KVSのサポートを行っています。 非同期メッセージングとして前述したようにREST指向のメッセージを粗粒度コンポーネント間でパイプライン的に流通させるモデルをとっています。現在はまだ実現できていませんが、CPS(Continuous Passing Style;継続渡しスタイル)的な処理の記述や、メッセージキューを媒介にした非同期処理などを取り込める構造になっています。 また、データストアのスケーラビリティについてはKVSを包含したデータアクセス基盤を用意しました。 KVSも、Redisのように本当のKey/Value対のデータストアもありますしGoogle App Engine DataStoreのようにISAM的なデータ構造を持っているものもあります。以上の点から、KVSといってもISAMデータ構造、要するに単純な表形式のデータ構造を扱うようにしています。 クラウドアプリケーションでは、一貫性重視の用途にはRDBMS、スケーラビリティ重視の用途にはKVSを使い分けることになります。その場合、RDBMSとKVS間でデータを持ちまわる処理も普通に行われるのでKVSとRDBMSに対する統一アクセス法が欲しくなります。 また、このアクセス法はREST指向アーキテクチャ上で使用することになるので、RESTとのシームレースに連携できることが必要です。 g3では上記の要件を満たす統一アクセス法をサポートしました。REST指向アーキテクチャに沿って普通に処理を記述するだけで、特に意識することなくKVSを使用することができます。(もちろん、KVSをスケールさせるためにはキーの選定など特別な考慮が必要になりますが、疎通レベルでは簡単に使えるというのも重要です。) なお、SQLを直接使用したアクセスも可能ですし、Javaを直接使ってJDBCを使用することもできるので、必要に応じて使い分けすることもできます。 &lt;br /&gt;&lt;h3&gt;&lt;a href="" name="doc1_id49"&gt;各種機能&lt;/a&gt; &lt;/h3&gt;実用上有用な機能として以下の機能を実装しました。 &lt;br /&gt;&lt;ul&gt;&lt;li&gt; Web Socket&lt;br /&gt;&lt;/li&gt;&lt;li&gt; Ext-JS対応&lt;br /&gt;&lt;/li&gt;&lt;li&gt; 各種クラウドサービス用ドライバ(Twitter, Google Calendar, Dropbox, Evernote)&lt;/li&gt;&lt;/ul&gt;こういった、各種Web技術、クラウドサービスの取り込みは、必要に応じて順次行っていく予定です。 &lt;br /&gt;&lt;h2&gt;&lt;a href="" name="doc1_id65"&gt;スコープ外の機能&lt;/a&gt; &lt;/h2&gt;g3の提供する機能という切り口とは別に、g3がスコープ外としている機能、後回しにしている機能が分かれば、g3の目的・意図が明確になると思います。 以下の機能はフレームワークの直接のスコープ外としています。 &lt;br /&gt;&lt;ul&gt;&lt;li&gt; Web MVCフレームワーク&lt;br /&gt;&lt;/li&gt;&lt;li&gt; テンプレートエンジン&lt;/li&gt;&lt;/ul&gt;Web MVCフレームワークやテンプレートエンジンは、まだまだ改良すべき点はあるでしょうが、基本的には枯れた技術であり、再発明する必要性が薄いことが一つ。それより重要なのが、HTML5/CSS3によるAjaxやiOS/Androidといったスマートデバイスの興隆によって、技術の重要性が低くなりそうということです。 レガシー技術はそのまま再利用することとして、イベント駆動や非同期コンポーネントフレームワークといった既存の技術ではカバーしていない技術の実現を中心に開発を進めています。 通常のWebアプリケーションを開発する場合にg3を用いる場合には、既存のWebフレームワークと併用することになります。 &lt;br /&gt;&lt;h2&gt;&lt;a href="" name="doc1_id77"&gt;次の段階で取り組むもの&lt;/a&gt; &lt;/h2&gt;以下の機能は、次の段階で取り組む予定にしています。 &lt;br /&gt;&lt;ul&gt;&lt;li&gt; DI(Dependency Injection)&lt;br /&gt;&lt;/li&gt;&lt;li&gt; OSGi&lt;br /&gt;&lt;/li&gt;&lt;li&gt; JMX&lt;br /&gt;&lt;/li&gt;&lt;li&gt; Android&lt;br /&gt;&lt;/li&gt;&lt;li&gt; TDD/BDD&lt;/li&gt;&lt;/ul&gt;実用化フェーズでは必要なのは分かっているものの、基本機能が定まっていない段階で取り組むのは時期尚早ということで、将来の拡張を意識しつつも当面の開発項目からは落としています。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7964484936470829118-1208802792275023857?l=modegramming.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://modegramming.blogspot.com/feeds/1208802792275023857/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://modegramming.blogspot.com/2011/07/g3.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/1208802792275023857'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/1208802792275023857'/><link rel='alternate' type='text/html' href='http://modegramming.blogspot.com/2011/07/g3.html' title='g3 (クラウド温泉@小樽)'/><author><name>asami</name><uri>http://www.blogger.com/profile/12083671403528595185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_4HtJQwbXqEY/S4sSwhKz5fI/AAAAAAAAAFs/IvXW6ca5RGE/S220/profile.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7964484936470829118.post-5894510565323842658</id><published>2011-06-29T08:30:00.002+09:00</published><updated>2011-07-11T06:31:52.533+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='simplemodeler'/><category scheme='http://www.blogger.com/atom/ns#' term='g3'/><category scheme='http://www.blogger.com/atom/ns#' term='g4'/><title type='text'>クラウド温泉＠小樽</title><content type='html'>正式の広報はまだですが、8月27日(土)/28日(日)に&lt;a href="http://www.facebook.com/home.php?sk=group_225282024151633"&gt;クラウド温泉@小樽&lt;/a&gt;が開催される予定です。温泉に浸かりながら、クラウドを肴に語り合いましょう、という企画です。&lt;br /&gt;&lt;br /&gt;ここ数年取り組んでいた、ScalaによるDSL駆動開発について、開発していたツールが形になってきたので、クラウド温泉でお披露目する予定です。&lt;br /&gt;&lt;br /&gt;DSL駆動開発の軸となるのがScala DSLコンパイラ&lt;a href="http://code.google.com/p/simplemodeler/"&gt;SimpleModeler&lt;/a&gt;です。当初は、SimpleModelerでモデルからクラウドプラットフォームのAPI上に対して直接クラウドアプリケーションの生成を試行していたわけですが、適切なアプリケーションフレームワークがないと自動生成もままならない、ということが分かりクラウドプラットフォーム向けにRESTメッセージングフレームワークである&lt;a href="http://code.google.com/p/goldenport3/"&gt;g3&lt;/a&gt;を開発しました。&lt;br /&gt;&lt;br /&gt;g3はAtomPubメッセージによるRESTを軸としてコンポーネントの連携動作を行うイベント駆動フレームワークです。&lt;br /&gt;&lt;br /&gt;g3はデータストアアクセスを含めてTomcatなどのWebサーバとGoogle App Engineの両方で動作します。できるだけ同じプログラムを色々なクラウド・プラットフォームで動作させることがg3の目的の一つです。&lt;br /&gt;&lt;br /&gt;また、クラウド時代にはUIが、伝統的なWeb UIからAjaxベースのGUIやスマートデバイスに移行することになります。このところ仕事でAndroidに取り組んでいたこともあり、Android向けのプログラム生成の基盤となるフレームワーク&lt;a href="https://github.com/asami/goldenport-android-library"&gt;g4&lt;/a&gt;を作ってみました。&lt;br /&gt;&lt;br /&gt;Androidのアプリケーションアーキテクチャは、以前「&lt;a href="http://modegramming.blogspot.com/2010/12/android.html"&gt;Androidのアーキテクチャ&lt;/a&gt;」で考えてみましたが、これをさらに発展させプログラムの自動生成に対応したものを実装しました。&lt;br /&gt;&lt;br /&gt;クラウド温泉のセッションでは、SimpleModelerからg3を使ったGoogle App Engineアプリケーションと、g4を使ったAndroidアプリケーションの自動生成のデモを行う予定です。自動生成したAndroidアプリケーションとGoogle App Engineはもちろん連携動作します。&lt;br /&gt;&lt;br /&gt;といいつつ、g3アプリケーション(App Engine)とg4アプリケーション(Android)の自動生成はこれから作るので(汗)、実際にデモまで辿りつけるかは分かりませんが、クラウド温泉を励みにして取り組んでいく予定です。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7964484936470829118-5894510565323842658?l=modegramming.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://modegramming.blogspot.com/feeds/5894510565323842658/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://modegramming.blogspot.com/2011/06/blog-post.html#comment-form' title='1 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/5894510565323842658'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/5894510565323842658'/><link rel='alternate' type='text/html' href='http://modegramming.blogspot.com/2011/06/blog-post.html' title='クラウド温泉＠小樽'/><author><name>asami</name><uri>http://www.blogger.com/profile/12083671403528595185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_4HtJQwbXqEY/S4sSwhKz5fI/AAAAAAAAAFs/IvXW6ca5RGE/S220/profile.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7964484936470829118.post-5948717550056953312</id><published>2011-05-31T18:15:00.001+09:00</published><updated>2011-05-31T18:15:00.738+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='simplemodeling'/><title type='text'>データストアのアクセス特性</title><content type='html'>&lt;p&gt;4月の中頃に書いていた記事の続きなんですが、ずいぶん間が空いてしまいました。そこでは、すこしモデリングの話題に寄り道しましたが、ドメインモデルとデータストアのマッピングの話題に戻りたいと思います。&lt;/p&gt;&lt;p&gt;ドメインモデルとデータストアのマッピングを考える上で重要なのがデータストアの分類です。データストアの分類軸として、色々なものが考えられますがその一つとして、データアクセス特性があります。&lt;/p&gt;&lt;p&gt;クラウドプラウドプラットフォームにおけるデータストアの性能特性と、アプリケーションのニーズの対応関係を整理し、アプリケーションの用途に合わせた性能特性を持つデータストアを選択することが重要になります。&lt;/p&gt;&lt;p&gt;RDBMS登場後は、データストアの選択もRDBMS一本でよかったのですが、クラウドプラットフォーム、NoSQLといった新しい技術の登場で、データストアの選択、あるいは使い分けがアーキテクチャ選択上、重要な要因になってきました。&lt;/p&gt;&lt;p&gt;そこで、データストア選択のための評価軸を整理しておくことにしました。現時点で思いつくのがアクセスパターン、アクセス方式、アクセスサイズです。他によいものあれば随時追加していきたいと思います。&lt;/p&gt;&lt;br /&gt;&lt;h2 id="doc1_id13"&gt;アクセスパターン&lt;/h2&gt;&lt;br /&gt;&lt;p class="first_ja"&gt;データストアに対するアクセスパターンとして以下の分類を使用します。&lt;/p&gt;&lt;br /&gt;&lt;dl&gt;&lt;dt&gt;read-only&lt;br /&gt;&lt;dd&gt;参照のみ。&lt;br /&gt;&lt;dt&gt;read-write&lt;br /&gt;&lt;dd&gt;参照と更新。&lt;br /&gt;&lt;dt&gt;read-mostly&lt;br /&gt;&lt;dd&gt;ほとんど参照、まれに更新。&lt;br /&gt;&lt;dt&gt;write-only&lt;br /&gt;&lt;dd&gt;書き込みのみ。&lt;/dl&gt;&lt;br /&gt;&lt;p&gt;read-writeが一番汎用的ですが、スケーラビリティの達成が困難になります。&lt;/p&gt;&lt;p&gt;その他の3つのアクセスパターンは、read-writeよりもアクセスの自由度が限定される分、スケーラビリティを高くする事ができます。&lt;/p&gt;&lt;p&gt;read-onlyは文字通り参照のみのアクセスで、更新処理はありません。このパターンでは、データの複製を必要な数だけ用意することができるので、スケーラビリティを高めることができます。&lt;/p&gt;&lt;p&gt;read-mostlyは分散技術でよく用いられる呼び方で、ほとんど参照のみで、たまに更新があるという特性です。この特性と、データの一貫性は厳密に制御しないという方式を組み合わせるとキャッシュを広範囲にわたって配布、共有できるのでスケーラビリティを大幅に向上させることができます。&lt;/p&gt;&lt;p&gt;write-onlyはアプリケーションからは書込みのみを行うパターンです。ログなどが典型例ですが、CQRSといったアーキテクチャではデータ投入にこのアクセスパターンを用います。&lt;/p&gt;&lt;p&gt;read-writeでは、データの一貫性を保つための制御に大きなオーバヘッドあり、write-onlyとすることでこのオーバヘッドを避けることができます。&lt;/p&gt;&lt;br /&gt;&lt;h2 id="doc1_id43"&gt;アクセス方式&lt;/h2&gt;&lt;br /&gt;&lt;p class="first_ja"&gt;アクセス方式として以下の分類を使用します。&lt;/p&gt;&lt;br /&gt;&lt;dl&gt;&lt;dt&gt;sequential&lt;br /&gt;&lt;dd&gt;シーケンシャルアクセス&lt;br /&gt;&lt;dt&gt;random&lt;br /&gt;&lt;dd&gt;ランダムアクセス&lt;/dl&gt;&lt;br /&gt;&lt;p&gt;sequentialは、データを先頭から最後尾まで連続でアクセスするアクセスパターンです。先頭から最後尾までの連続アクセスも、さらに索引順と格納順に分けることができますが、現在は索引を持つのが普通(あるいはカラムナDB)なので考えないことにします。&lt;/p&gt;&lt;p&gt;randomは、データを一部をランダムにアクセスするアクセスパターンです。&lt;/p&gt;&lt;p&gt;OLTPはランダムアクセスが中心ですが、バッチ処理やOLAP/BIはシーケンシャルアクセスのニーズが高くなります。&lt;/p&gt;&lt;p&gt;データストアを選択する上で重要なのは、ランダムアクセス性能とシーケンシャルアクセス性能は、多くの場合相反する性質ということです。このため、アプリケーションの特性に応じてデータストア製品を選択するが必要となります。あるいは、RDBMSにおけるインデックスのチューニングといった作業で同じデータベースシステムをシーケンシャルアクセス向けやランダムアクセス向けにチューニング仕分けることも可能です。いずれかの手段で、適切なデータストアを確保することになります。&lt;/p&gt;&lt;br /&gt;&lt;h2 id="doc1_id62"&gt;アクセスサイズ&lt;/h2&gt;&lt;br /&gt;&lt;p class="first_ja"&gt;アクセスサイズとして以下の分類を使用します。&lt;/p&gt;&lt;br /&gt;&lt;dl&gt;&lt;dt&gt;record&lt;br /&gt;&lt;dd&gt;データをレコード単位でアクセス&lt;br /&gt;&lt;dt&gt;portion&lt;br /&gt;&lt;dd&gt;データの一定範囲をアクセス&lt;br /&gt;&lt;dt&gt;bulk&lt;br /&gt;&lt;dd&gt;データの一定範囲/全体を一括してアクセス&lt;/dl&gt;&lt;br /&gt;&lt;p&gt;recordはレコード単位でのデータアクセスです。1レコードから数レコードの範囲を想定しています。&lt;/p&gt;&lt;p&gt;portionは一定範囲でのデータアクセスです。データの選択を行った後、一回の転送で取得できる範囲(1000件程度)を想定しています。&lt;/p&gt;&lt;p&gt;bulkはデータの一定範囲あるいは全体を一括アクセスします。データ全体スキャンあるいは選択条件に合致する多量のレコードを一括してアクセスすることを想定しています。&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7964484936470829118-5948717550056953312?l=modegramming.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://modegramming.blogspot.com/feeds/5948717550056953312/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://modegramming.blogspot.com/2011/05/blog-post.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/5948717550056953312'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/5948717550056953312'/><link rel='alternate' type='text/html' href='http://modegramming.blogspot.com/2011/05/blog-post.html' title='データストアのアクセス特性'/><author><name>asami</name><uri>http://www.blogger.com/profile/12083671403528595185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_4HtJQwbXqEY/S4sSwhKz5fI/AAAAAAAAAFs/IvXW6ca5RGE/S220/profile.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7964484936470829118.post-3637025511710117950</id><published>2011-04-15T07:15:00.001+09:00</published><updated>2011-04-15T07:15:02.270+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='simplemodeling'/><title type='text'>ユースケース</title><content type='html'>&lt;p&gt;コラボレーション&lt;b&gt;タスク監視起票&lt;/b&gt;は、Twitterでの注目発言の発生を監視し、注目発言が発生したときに、この発言に対応するためのタスクを起票するコラボレーションです。&lt;/p&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-RGjkLXk64uc/TaaO0sghE6I/AAAAAAAAALE/tvQUn7INDp4/s1600/mappingRuleX1.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" height="251" src="http://1.bp.blogspot.com/-RGjkLXk64uc/TaaO0sghE6I/AAAAAAAAALE/tvQUn7INDp4/s320/mappingRuleX1.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;アプリケーション開発におけるモデリング作業の中でこのコラボレーションをどのように抽出してくるのかというのが論点の一つになります。これは、利用者の要求とコラボレーションの結びつけるモデル要素が必要なことを意味しています。&lt;/p&gt;&lt;p&gt;いうまでもなく、このモデル要素とはユースケース(use case)です。ユースケースは、システムの振舞いモデルであると同時に利用者の目的と、目的を達成するための物語を記述したモデル要素です。&lt;/p&gt;&lt;p&gt;ユースケースは、アクターの目的をアクターとシステム間のインタラクションの列として記述します。通常は、自然言語によるシナリオとしてこのインタラクションを記述します。&lt;/p&gt;&lt;p&gt;UMLでは、ユースケースを具象化したものがコラボレーション、コラボレーションを抽象化したものがユースケースという関係になります。&lt;/p&gt;&lt;br /&gt;&lt;p&gt;以下の図はコラボレーション&lt;b&gt;イベント監視タスク起票&lt;/b&gt;を利用者の要求と結びつけるユースケースであるユースケース&lt;b&gt;イベントを監視して対応するタスクを起票する&lt;/b&gt;を追加したものです。ユースケース&lt;b&gt;イベントを監視して対応するタスクを起票する&lt;/b&gt;は、利用者視点での利用者とシステムのインタラクションをシナリオとして記述します。&lt;/p&gt;&lt;p&gt;そして、コラボレーション&lt;b&gt;イベント監視タスク起票&lt;/b&gt;はこのユースケース&lt;b&gt;イベントを監視して対応するタスクを起票する&lt;/b&gt;を実現(realize)する、という関係(relationship)になるわけです。(UMLでは、ユースケースをコラボレーションが実現するという関係を、実現シンボル(典型的にはインタフェースをクラスが実現の用途で使用)で記述できるのですがJudeではサポートしていないようなので、依存(dependency)で記述しています。)&lt;/p&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-ebKnoJdOZRw/TaaO3MyQDbI/AAAAAAAAALI/mIDl3YDfb70/s1600/mappingRuleX2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="342" src="http://1.bp.blogspot.com/-ebKnoJdOZRw/TaaO3MyQDbI/AAAAAAAAALI/mIDl3YDfb70/s400/mappingRuleX2.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;開発の手順としては、問題領域のドメインモデルをざっくりと作りつつ、利用者の要求をユースケースとしてモデル化。ユースケースを実現するためにドメインモデルを調整、という流れになります。&lt;/p&gt;&lt;p&gt;ここで、ユースケースとドメインモデルをつなぐモデル要素としてコラボレーションが登場することになります。このコラボレーションをコードの自動生成の枠組みに結びつけることができれば、自動生成のターゲットが大きく広がります。&lt;/p&gt;&lt;p&gt;SimpleModelerでは、ユースケース、コラボレーションをScala DSLで記述して、(同じくScala DSLで記述した)ドメインモデルと結びつけるような方向でユースケースからコラボレーションを経てドメインモデルに至るトータルなモデリングプラットフォームを提供したいと考えています。&lt;/p&gt;&lt;p&gt;ユースケース周りは、ロバストネス分析など色々とおもしろい話題があるので、SimpleModelingでの扱い、SimpleModelerでのサポート方針といった切り口でブログでも取り上げていきたいと思います。&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7964484936470829118-3637025511710117950?l=modegramming.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://modegramming.blogspot.com/feeds/3637025511710117950/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://modegramming.blogspot.com/2011/04/blog-post_15.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/3637025511710117950'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/3637025511710117950'/><link rel='alternate' type='text/html' href='http://modegramming.blogspot.com/2011/04/blog-post_15.html' title='ユースケース'/><author><name>asami</name><uri>http://www.blogger.com/profile/12083671403528595185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_4HtJQwbXqEY/S4sSwhKz5fI/AAAAAAAAAFs/IvXW6ca5RGE/S220/profile.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-RGjkLXk64uc/TaaO0sghE6I/AAAAAAAAALE/tvQUn7INDp4/s72-c/mappingRuleX1.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7964484936470829118.post-5945322142606124664</id><published>2011-04-14T18:00:00.002+09:00</published><updated>2011-04-15T04:01:28.519+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='simplemodeling'/><title type='text'>コラボレーションと拡張点</title><content type='html'>コラボレーション&lt;b&gt;イベント監視タスク起票&lt;/b&gt;は、Twitterでの注目発言の発生を監視し、注目発言が発生したときに、この発言に対応するためのタスクを起票するコラボレーションです。&lt;br /&gt;&lt;br /&gt;&lt;div class="figure"&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-oMZe15LN0h8/TaN0yPBxWSI/AAAAAAAAAK4/G0lXgTEi1L4/s1600/mappingRule.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="281" src="http://4.bp.blogspot.com/-oMZe15LN0h8/TaN0yPBxWSI/AAAAAAAAAK4/G0lXgTEi1L4/s400/mappingRule.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;話のそれついでにコラボレーションに関連するモデリング上の話題を続けます。&lt;br /&gt;コラボレーションの導入はコードの自動生成が重要な目的です。&lt;br /&gt;コード生成を行うためには、模型的な意味で図形が配置されているだけでは情報量は不十分で、より詳細な情報を記述しなければなりません。&lt;br /&gt;このような情報の一つに前回の記事で説明した「ドメインルールはTemplateMethodの骨組みのスロットに差し込む拡張部。アプリケーションの構成定義画面でパラメタの変更が可能」といったものがあります。&lt;br /&gt;つまり、ドメインルールのところで、カスタマイズが可能なわけですが、コラボレーション側でもカスタマイズが必要な場合があります。&lt;br /&gt;この目的に、UML標準部品である拡張点(extension point)を用いることができます。拡張点は(通常はユースケースに使うのですが)コラボレーションのインタラクションの一部を拡張するためのスロット的なポイントです。拡張点名を記述し、それに対する具体的な拡張のコラボレーションを拡張(extend)関係で記述します。&lt;br /&gt;拡張点を用いて、コラボレーション&lt;b&gt;イベント監視タスク起票&lt;/b&gt;のより詳細な情報を記述した図が以下のものです。&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-RGjkLXk64uc/TaaO0sghE6I/AAAAAAAAALE/tvQUn7INDp4/s1600/mappingRuleX1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="313" src="http://1.bp.blogspot.com/-RGjkLXk64uc/TaaO0sghE6I/AAAAAAAAALE/tvQUn7INDp4/s400/mappingRuleX1.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;コラボレーション&lt;b&gt;イベント監視タスク起票&lt;/b&gt;は、拡張点&lt;b&gt;イベント監視&lt;/b&gt;を持っており、ここに拡張を実現するコラボレーションとしてコラボレーション&lt;b&gt;注目発言拡張&lt;/b&gt;を指定しているので、注目発言を監視するコラボレーションとして動作する、というわけです。(補足ですが、この図の趣旨からは、注目発言ピックアップの対象がTwetterとなっているのは、DoainRule&lt;b&gt;注目発言ピックアップ&lt;/b&gt;の設定、ということになります。&lt;br /&gt;この他にもコラボレーションをカスタマイズするメカニズムとしてステレオタイプ、タグ付き値を使用することができます。&lt;br /&gt;UMLでカスタマイズを記述するとこの図のような形になるわけですが、これでは情報が不足ではないか、と思われるかもしれません。&lt;br /&gt;実際のところ、その通りで、本当にコードの自動生成を行うということであれば、相当量の情報をタグ付き値などを使って設定しなければなりません。&lt;br /&gt;つまるところ、UMLでモデルを記述する場合でも、結局のところ情報の過半数はテキスト情報として入力しなければならないわけです。そうであれば、始めからテキスト形式の言語で記述したほうがよい、というのがSimpleModelerのアプローチです。&lt;br /&gt;テキスト情報から、上記の図レベルのものはプログラムで生成することが可能です。どのコラボレーションにどのような拡張点があるのか、といった情報をざっくり見るにはツールが生成した図を見れば十分であり、わざわざモデリング時に手で入力する必要はないわけです。&lt;br /&gt;SimpleModelerでは、コラボレーションとドメインルールによって、アプリケーションの振舞いのプレースホルダーを記述し、ここから実行フレームワーク上で動作するコード(フレームワークの設定情報になるかもしれない)を生成するという方向で、アプリケーションの振舞いをコードに落とすことを考えています。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7964484936470829118-5945322142606124664?l=modegramming.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://modegramming.blogspot.com/feeds/5945322142606124664/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://modegramming.blogspot.com/2011/04/blog-post_14.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/5945322142606124664'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/5945322142606124664'/><link rel='alternate' type='text/html' href='http://modegramming.blogspot.com/2011/04/blog-post_14.html' title='コラボレーションと拡張点'/><author><name>asami</name><uri>http://www.blogger.com/profile/12083671403528595185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_4HtJQwbXqEY/S4sSwhKz5fI/AAAAAAAAAFs/IvXW6ca5RGE/S220/profile.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-oMZe15LN0h8/TaN0yPBxWSI/AAAAAAAAAK4/G0lXgTEi1L4/s72-c/mappingRule.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7964484936470829118.post-879252252730235355</id><published>2011-04-13T08:36:00.000+09:00</published><updated>2011-04-13T08:36:28.086+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='simplemodeling'/><title type='text'>コラボレーション</title><content type='html'>ドメインモデルにおけるロジックの抽出、記述方式について検討しています。&lt;br /&gt;前々回にドメインモデルの例として以下の図を作成しました。これは、ServiceEvent、ServiceResourceの導入がクラウド向けの工夫ですが、基本的には従来からあるドメインモデルの静的構造側面を記述しています。&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-z5XHchmR-NI/TaN00otLWrI/AAAAAAAAAK8/KeiSzlRdPa0/s1600/mappingRule0.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="223" src="http://3.bp.blogspot.com/-z5XHchmR-NI/TaN00otLWrI/AAAAAAAAAK8/KeiSzlRdPa0/s400/mappingRule0.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;前回は、ドメインオブジェクトとしてDomainRuleを導入することで、ドメインロジックをドメインモデルとして記述できるようにしました。それが以下の図です。&lt;br /&gt;&lt;br /&gt;&lt;div class="figure"&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-afNASrML5jo/TaN02v1P3oI/AAAAAAAAALA/5kfVsKSGDNQ/s1600/mappingRule1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="223" src="http://2.bp.blogspot.com/-afNASrML5jo/TaN02v1P3oI/AAAAAAAAALA/5kfVsKSGDNQ/s400/mappingRule1.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;ドメインルールはあくまでもルールを記述するオブジェクトなので、記述するロジックも受動的なものになります。何かの処理の中で、ドメインが内包しているルール(たとえば消費税の計算)を使用するというのが、ドメインルールの基本的な使い方になります。&lt;br /&gt;つまり、受動的なロジックであるルールを駆動する能動的なロジックが必要になるわけです。この能動的なロジックの記述はドメインモデルではなく、アプリケーションモデルとしてモデル化するのがSimpleModelingのアプローチです。アプリケーションモデルは、アプリケーションの利用者が目的を達成するための構造、振る舞いを記述するモデルです。アプリケーションモデルは、アプリケーションの文脈(プロダクトライン、ユースケースファミリなど)として定義されているドメインモデルを操作して、利用者の目標(目的を具体化した物)を達成していきます。SimpleModelingのモデリングアーキテクチャにおけるドメインモデルとアプリケーションモデルの位置付け、関係についてはいずれ説明したいと思います。&lt;br /&gt;ここでは、アプリケーションを構成する能動的なロジックは基本的にアプリケーションモデルで定義するのが基本的な考え方として検討を進めます。&lt;br /&gt;アプリケーションロジックの網羅的な抽出や詳細化はアプリケーションモデルを作成する段階で行うとしても、ドメインモデルの段階でもある程度の抽出は可能です。また、ドメインモデルの構造もアプリケーションモデルから利用可能な形に調整する必要があるので、ドメインモデルを作成する段階で代表的なアプリケーションロジックを記述しておくのは有用です。&lt;br /&gt;アプリケーションロジックの抽出をこの段階で行うのはやや早い感もありますが、代表的な物を明確にしておくことは、モデルの目的を明確化することになるので、分かっている範囲で行っておくのがよさそうです。&lt;br /&gt;アプリケーションロジックについては、ユースケース分析の中で網羅的に抽出し、ドメインモデルに反映していくことになります。&lt;br /&gt;この目的で導入するモデル要素がコラボレーション(collaboration,協調)です。コラボレーションは、UMLの標準モデル要素でオブジェクト間のメッセージの送受信であるインタラクション(interaction)を(目標を達成する単位で)束ねたものです。(UML1とUML2でコラボレーションの定義が変わってしまったのですが、ここではUML1的な意味で使っています。)&lt;br /&gt;コラボレーション&lt;b&gt;イベント監視タスク起票&lt;/b&gt;を追加したドメインモデルは以下の図となります。ボクの使っているJudeではコラボレーションシンボルが使えないみたいなのでユースケースシンボルにステレオタイプcollaborationを記述して代用しています。(UMLのコラボレーションシンボルは破線の楕円です。)&lt;br /&gt;&lt;br /&gt;&lt;div class="figure"&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-oMZe15LN0h8/TaN0yPBxWSI/AAAAAAAAAK4/G0lXgTEi1L4/s1600/mappingRule.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="281" src="http://4.bp.blogspot.com/-oMZe15LN0h8/TaN0yPBxWSI/AAAAAAAAAK4/G0lXgTEi1L4/s400/mappingRule.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;コラボレーション&lt;b&gt;タスク監視起票&lt;/b&gt;は、Twitterでの注目発言の発生を監視し、注目発言が発生したときに、この発言に対応するためのタスクを起票するコラボレーションです。このコラボレーションがアプリケーションロジックに落とし込まれていくことになります。&lt;br /&gt;この段階でコラボレーションを記述する目的の一つは、ドメインモデルの精度を高めるという目的に加えて、自動生成の対象を抽出という目的もあります。このあたりは、ドメインルールを導入するのと同じ目的です。&lt;br /&gt;つまり、コードの自動生成のプレースホルダーとしての役割、さらにフレームワークと連動できるコラボレーションは、実行可能レベルのコード生成が可能になるでしょう。&lt;br /&gt;以上のようにドメインモデルを振る舞いの視点でみるとコラボレーション、ドメインルール、ドメインエンティティの3階層で構成されます。この階層をモデル要素の関係を実装レベルで考えてみると以下のようなイメージになります。&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt; コラボレーションはTemplateMethodパターン的な処理部。&lt;br /&gt;&lt;/li&gt;&lt;li&gt; ドメインルールはTemplateMethodの骨組みのスロットに差し込む拡張部。アプリケーションの構成定義画面でパラメタの変更が可能。&lt;br /&gt;&lt;/li&gt;&lt;li&gt; ドメインエンティティはデータベースに格納されるデータまたはサービスとやり取りするデータ。&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7964484936470829118-879252252730235355?l=modegramming.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://modegramming.blogspot.com/feeds/879252252730235355/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://modegramming.blogspot.com/2011/04/blog-post_13.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/879252252730235355'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/879252252730235355'/><link rel='alternate' type='text/html' href='http://modegramming.blogspot.com/2011/04/blog-post_13.html' title='コラボレーション'/><author><name>asami</name><uri>http://www.blogger.com/profile/12083671403528595185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_4HtJQwbXqEY/S4sSwhKz5fI/AAAAAAAAAFs/IvXW6ca5RGE/S220/profile.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-z5XHchmR-NI/TaN00otLWrI/AAAAAAAAAK8/KeiSzlRdPa0/s72-c/mappingRule0.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7964484936470829118.post-4369868762052174677</id><published>2011-04-12T06:46:00.001+09:00</published><updated>2011-04-12T06:47:19.561+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='simplemodeler'/><category scheme='http://www.blogger.com/atom/ns#' term='g3'/><category scheme='http://www.blogger.com/atom/ns#' term='simplemodeling'/><title type='text'>ドメインルール</title><content type='html'>前回はエンティティ間の静的な関係(relationship)を定義する以下のドメインモデルを作成しました。モデル駆動開発によるコードの自動生成でも、この範囲の自動生成はすでに実用化または実用化の射程距離内です。&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-z5XHchmR-NI/TaN00otLWrI/AAAAAAAAAK8/KeiSzlRdPa0/s1600/mappingRule0.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="223" src="http://3.bp.blogspot.com/-z5XHchmR-NI/TaN00otLWrI/AAAAAAAAAK8/KeiSzlRdPa0/s400/mappingRule0.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;ドメインモデルの重要な軸は(このモデルが典型的な例ですが)問題領域の静的な構造の記述です。従来のアプローチは、データベースに格納するデータとデータ間の構造が中心でしたが、ServiceEventやServiceResourceの導入によって、クラウド上のイベントやリソースもスコープ内に取り込もうというのがここまでの試みです。&lt;br /&gt;クラウドアプリケーションのニーズに対応した形で自動生成の対象範囲が広がりますが、データの範囲をスコープにしているという意味では従来路線を踏襲した漸進的なアプローチともいえます。もう一段、コードの生成範囲を広げられないでしょうか。&lt;br /&gt;モデル駆動開発の問題点の一つは、オブジェクトモデルとしてロジックを宣言的、形式的に記述する方法が確立されていない点です。UMLできちんと記述できるのは状態機械図まで。シーケンス図/コミュニケーション図(旧コラボレーション図)は一応演繹的にも記述できることになっていますが、実用上はインタラクションのインスタンスを具体例として記述するものと考えた方がよさそうです。OCL(Object Constraint Language)は有用ですが、文字通り制約を記述するための言語なので適用範囲が限られます。MDA(Model Driven Architecture)の基盤となるxUML(Executable UML)はこの部分をAction Language (MDA的にはAction Semanticsとその実現言語)で補完していますが、Action Languageは状態機械との連動がオブジェクト指向的には進化であるとはいえ(大多数のオブジェクト指向型言語がそうであるように)手続き型折衷オブジェクト指向プログラミング言語みたいなものであり、現時点の技術では手続き型プログラミング言語を導入しないとロジック記述の問題は解決しないと考えてよさそうです。(いずれこの部分を関数型言語や論理型言語が埋めていくことになるでしょうが、まだまだ先の話です。)&lt;br /&gt;どちみちプログラミング言語的な記述が必要なのであれば、ActionLanguageを使うより、使い慣れているScalaやJava(その他お好みの言語)でロジックは書きたいところです。&lt;br /&gt;そこで、コードの自動生成の対象範囲を広げるための仕掛けとしてSimpleModelingが用意しているドメインモデルのモデル要素がドメインルール(ステレオタイプDomainRule)です。ドメインルールは、ドメインに存在するロジック、責務の中でルールとして扱うと適切なものをオブジェクト化したものです。ドメインルールは以前から導入済みですが、クラウド時代でも引き続き有効なドメインオブジェクトです。&lt;br /&gt;ドメインモデルの中でロジックを記述する方法としては、エンティティオブジェクトのオペレーションとして定義する方法もあります。ドメインルールとはケースバイケースで使い分けることになります。&lt;br /&gt;オペレーションとドメインルールの選択は以下の項目を目安にするとよいでしょう。&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt; アプリケーションのカスタマイズ項目になりそうなものはドメインルール。&lt;br /&gt;&lt;/li&gt;&lt;li&gt; 複数のドメインオブジェクトを横断的に操作するものはドメインルール。&lt;/li&gt;&lt;/ul&gt;ドメインルールを追加したドメインモデルは以下の通りです。&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-afNASrML5jo/TaN02v1P3oI/AAAAAAAAALA/5kfVsKSGDNQ/s1600/mappingRule1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="223" src="http://2.bp.blogspot.com/-afNASrML5jo/TaN02v1P3oI/AAAAAAAAALA/5kfVsKSGDNQ/s400/mappingRule1.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;以下の3つのドメインルールを追加しています。&lt;br /&gt;&lt;dl&gt;&lt;dt&gt;注目発言ピックアップ&lt;br /&gt;&lt;/dt&gt;&lt;dd&gt;Twitterからツイートを検出するルール&lt;/dd&gt;&lt;dt&gt;タスク生成&lt;br /&gt;&lt;/dt&gt;&lt;dd&gt;タスクを生成するルール&lt;/dd&gt;&lt;dt&gt;対応選択&lt;br /&gt;&lt;/dt&gt;&lt;dd&gt;Twitterのツイートから対応を選択するルール&lt;/dd&gt;&lt;/dl&gt;DomainRule&lt;b&gt;対応選択&lt;/b&gt;は、DomainRule&lt;b&gt;タスク生成&lt;/b&gt;と合成(composition aggregation)の関係になっており、&lt;b&gt;タスク生成&lt;/b&gt;の一部として動作します。&lt;br /&gt;この例では、ドメインルールからドメインイベントやドメインリソースに対する使用(use dependency)を行っていますが、逆にドメインイベントやドメインリソースからドメインルールへの使用(use dependency)もありえます。例えば、消費税計算ルールを請求書発行イベントから使用するといったケースです。&lt;br /&gt;ドメインルールは、ドメインモデルの中でルールを特定するプレースホルダーの役割を担います。前述したようにUMLではロジックを記述できないので、ドメインモデルでできることはここまでという割り切りです。&lt;br /&gt;ただし、ステレオタイプやタグ付き値、関連端(association end)といった修飾パラメタによって生成するコードを特定することができる可能性があります。&lt;br /&gt;たとえば、DomainRule&lt;b&gt;タスク生成&lt;/b&gt;はfactoryというステレオタイプが付いていますが、適切なパラメタを与えればファクトリオブジェクトの実装に落とし込むことは技術的に可能でしょう。&lt;br /&gt;実行プラットフォーム上で動作するフレームワークによって、相当な種類のドメインルールに対応する機能の受け口を実現できるはずです。このようにプラットフォームで対応済みのルールをドメインモデル上で使用することで、ドメインモデルからコード生成できる範囲が格段に広がるでしょう。&lt;br /&gt;また、自動生成には至らなかった場合でも、ロジックのプレースフォルダーとしての存在意義は十分にあります。少なくても、アプリケーションに組み込むためのSPI(Service Provider Interface)といったものの自動生成は可能で、これだけでもずいぶん違うはずです。&lt;br /&gt;ボクが開発しているDSLコンパイラSimpleModelerとマッシュアップフレームワークg3では、このような連携ができることを目指しています。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7964484936470829118-4369868762052174677?l=modegramming.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://modegramming.blogspot.com/feeds/4369868762052174677/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://modegramming.blogspot.com/2011/04/blog-post_12.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/4369868762052174677'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/4369868762052174677'/><link rel='alternate' type='text/html' href='http://modegramming.blogspot.com/2011/04/blog-post_12.html' title='ドメインルール'/><author><name>asami</name><uri>http://www.blogger.com/profile/12083671403528595185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_4HtJQwbXqEY/S4sSwhKz5fI/AAAAAAAAAFs/IvXW6ca5RGE/S220/profile.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-z5XHchmR-NI/TaN00otLWrI/AAAAAAAAAK8/KeiSzlRdPa0/s72-c/mappingRule0.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7964484936470829118.post-4690630073062229556</id><published>2011-04-11T08:10:00.000+09:00</published><updated>2011-04-11T08:10:11.971+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='simplemodeling'/><title type='text'>ドメインモデルを具体的に考えてみる</title><content type='html'>ドメインモデルとデータストアのマッピングについて検討を始めたところで、話がだいぶそれてきましたが、もう少しそれてみたいと思います。&lt;br /&gt;DomainResourceとServiceResourceを導入したので、試しにDomainResourceとServiceResourceが混在するドメインモデルについて具体的に考えてみました。&lt;br /&gt;以下の図はTwitterのタイムラインを監視して、何らかの基準に沿ったツイートを検出し、何かの対応をすることを管理するタスクを起票するアプリケーションのドメインモデルです。タスクはNozbeのタスクとBacklogの課題として2つのサービスに同時に作成します。&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-7w85fZput84/TaI4laImCeI/AAAAAAAAAKw/IsWLCVVhh08/s1600/mappingRule0.png" imageanchor="1" style=""&gt;&lt;img border="0" height="224" width="400" src="http://4.bp.blogspot.com/-7w85fZput84/TaI4laImCeI/AAAAAAAAAKw/IsWLCVVhh08/s400/mappingRule0.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;こういったNozbeのタスクやBacklogの課題といった「概念」上は抽象の中に隠蔽されるオブジェクトをPIM段階のドメインモデルでどう扱うのか、というのが論点の一つ、というのがここまでの話でした。DomainResourceとServiceResourceを導入したメタモデルでは、抽象「概念」として隠蔽したいケース、具象「概念」として明示したいケースの両方に対応できるというのがミソです。&lt;br /&gt;この図は具象概念として明示したいケースになります。&lt;br /&gt;ドメインモデルでタスクとして扱うものは、実際には主にNozbeとBacklog上で利用者からの操作を行うことを想定しています。しかし、NozbeとBacklog間の同期やアプリケーション側での操作の目的で、自前のデータベースで管理するオブジェクトも必要になります。このオブジェクトがDomainResource&lt;b&gt;タスク&lt;/b&gt;です。そして、&lt;b&gt;タスク&lt;/b&gt;から&lt;b&gt;NozbeTask&lt;/b&gt;と&lt;b&gt;Backlog課題&lt;/b&gt;を集約(aggregation)します。&lt;br /&gt;一方、アプリケーションが扱うイベントとしてDomainEvent&lt;b&gt;タスク起票&lt;/b&gt;とServiceEvent&lt;b&gt;Tweet発生&lt;/b&gt;を定義しています。よりモデルの汎用化を進めるならServiceEvent&lt;b&gt;Tweet発生&lt;/b&gt;に対応するDomainEvent&lt;b&gt;Tweet発生&lt;/b&gt;を定義して抽象化しておくというアプローチも考えられます。&lt;br /&gt;ドメインモデルの記述対象のスコープにも色々な切り口がありますが、一般的なのはデータベースに格納するデータの範囲です。この図の場合、DomainEvent&lt;b&gt;タスク起票&lt;/b&gt;, DomainResource&lt;b&gt;タスク&lt;/b&gt;がこれに当たります。&lt;br /&gt;モデル駆動開発によるコードの自動生成でも、データベースに格納するオブジェクトの範囲の自動生成はすでに実用化されており、安定状態にある技術です。つまり、DomainEvent&lt;b&gt;タスク起票&lt;/b&gt;, DomainResource&lt;b&gt;タスク&lt;/b&gt;は自動生成のスコープ内に入ってきます。&lt;br /&gt;しかし、ドメインモデルの記述がこの範囲であれば、自動生成の対象範囲もここまでということになります。&lt;br /&gt;ServiceResourceやServiceEventといった外部サービスが提供するドメインオブジェクトを導入する目的は、もちろんドメインモデルの精度を上げることもありますが、実利的にはサービスが生成するイベントやリソースに対応するコードの自動生成を行える可能性が出てくることが大きいでしょう。&lt;br /&gt;ServiceResourceやServiceEventをドメインモデル上で扱うことによって、twitterのストリームを監視したり、RESTで各種サービスのリソースに対してアクセスをしたりといったコードを生成することは技術的には十分射程範囲です。こういった、アプリケーションの部品として何回も何回も繰り返し作り続けられている処理を定型化して、自動生成の対象にできることが、モデリングという要求と実装の中間に位置する作業を行う具体的な価値であり、大きな動機です。このスコープを広げるために、ドメインモデルのメタモデルの拡張と、メタモデルと実装とのマッピングを進めていくことが重要となってきます。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7964484936470829118-4690630073062229556?l=modegramming.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://modegramming.blogspot.com/feeds/4690630073062229556/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://modegramming.blogspot.com/2011/04/blog-post_11.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/4690630073062229556'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/4690630073062229556'/><link rel='alternate' type='text/html' href='http://modegramming.blogspot.com/2011/04/blog-post_11.html' title='ドメインモデルを具体的に考えてみる'/><author><name>asami</name><uri>http://www.blogger.com/profile/12083671403528595185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_4HtJQwbXqEY/S4sSwhKz5fI/AAAAAAAAAFs/IvXW6ca5RGE/S220/profile.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-7w85fZput84/TaI4laImCeI/AAAAAAAAAKw/IsWLCVVhh08/s72-c/mappingRule0.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7964484936470829118.post-3528551750648216408</id><published>2011-04-08T08:01:00.000+09:00</published><updated>2011-04-08T08:01:05.521+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='simplemodeling'/><title type='text'>メタモデルとステレオタイプ</title><content type='html'>PIM段階のドメインモデルで、自前管理のオブジェクトと他サービス管理のオブジェクトの区別をするのか、その区別はPSM段階まで留保しておくのか。&lt;br /&gt;一意的に決めてしまうのは難しい問題で、ケースバイケースで選択したいところです。短手番でサービスをマッシュアップしてアプリケーションを構築する用途では前者のニーズが高そうですし、長期間にわたって持続的にシステム構築を続けていく、基幹システムでは後者のニーズが高いでしょう。&lt;br /&gt;SimpleModelingは、どちらかというと前者の用途をターゲットにしているので、前者向けに特化したメタモデルを整備しても良いのですが、場合によっては後者の応用にも対応できるのに越したことはありません。&lt;br /&gt;そういったことをつらつらと考えている中で、思いついたのは以下の図のメタモデルです。&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-LUaF7dASDCY/TZ4_mGb_SyI/AAAAAAAAAKc/EqQmT0ruOR8/s1600/MetaModel.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="271" src="http://1.bp.blogspot.com/-LUaF7dASDCY/TZ4_mGb_SyI/AAAAAAAAAKc/EqQmT0ruOR8/s400/MetaModel.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;以下のメタオブジェクトが定義されています。&lt;br /&gt;&lt;br /&gt;&lt;dl&gt;&lt;dt&gt;Entity&lt;br /&gt;&lt;/dt&gt;&lt;dd&gt;アプリケーションが永続的に使用するオブジェクト&lt;/dd&gt;&lt;dt&gt;DomainResource&lt;br /&gt;&lt;/dt&gt;&lt;dd&gt;Resourceタイプのドメインオブジェクト&lt;/dd&gt;&lt;dt&gt;ManagedEntity&lt;br /&gt;&lt;/dt&gt;&lt;dd&gt;アプリケーションの管理下にあるEntity&lt;/dd&gt;&lt;dt&gt;ServiceEntity&lt;br /&gt;&lt;/dt&gt;&lt;dd&gt;他サービスの管理下にあるEntity&lt;/dd&gt;&lt;dt&gt;ManagedDomainResource&lt;br /&gt;&lt;/dt&gt;&lt;dd&gt;アプリケーションの管理下にあるDomainResource&lt;/dd&gt;&lt;dt&gt;ServiceDomainResource&lt;br /&gt;&lt;/dt&gt;&lt;dd&gt;他サービスの管理下にあるDomainResource&lt;/dd&gt;&lt;dt&gt;ServiceResource&lt;br /&gt;&lt;/dt&gt;&lt;dd&gt;ServiceDomainResourceの別名&lt;/dd&gt;&lt;/dl&gt;&lt;br /&gt;EntityとDomainResourceが元々あったメタオブジェクト。SimpleModelingのメタオブジェクト全体でアプリケーションが永続的に使用するオブジェクトがEntity。Entityの一種でドメインモデルのリソースオブジェクトがDomainResourceとなります。&lt;br /&gt;ManagedEntityとServiceEntityは、EntityにミックスインしてEntityの所属を記述するために追加したメタオブジェクトです。&lt;br /&gt;そして、DomainResourceかつManagedEntityなドメインオブジェクトがManagedDomainResource、DomainResourceかつServiceEntityなドメインオブジェクトがServiceDomainResourceです。&lt;br /&gt;さらに、ServiceDomainResourceの別名としてServiceResourceを用意します。&lt;br /&gt;このメタモデルをステレオタイプで表現したクラス図表現は以下のようになります。&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-SNRY-WxLXpQ/TZ4_qaUN8NI/AAAAAAAAAKg/xNLPsR8t4qE/s1600/Stereotype.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="72" src="http://1.bp.blogspot.com/-SNRY-WxLXpQ/TZ4_qaUN8NI/AAAAAAAAAKg/xNLPsR8t4qE/s400/Stereotype.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;このステレオタイプの使用方法は以下の2パターンを念頭においています。&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt; DomainResourceはManagedDomainResourceの省略形として用い、ServiceResourceと組合せて使うことで、PIM段階で自前エンティティと他サービスエンティティを区別しながらモデリングを行う。&lt;br /&gt;&lt;/li&gt;&lt;li&gt; PIM段階ではDomainResourceとしておき、PSM段階でManagedEntityやServiceEntityを追加し定義して、自前エンティティと他サービスエンティティを区別する。&lt;/li&gt;&lt;/ol&gt;具体例でみていきましょう。&lt;br /&gt;(1)ServiceResourceを使う場合は以下のようになります。DomainResourceと同様に拡張を行ったDomainEventも使用しています。&lt;b&gt;Tweet発生&lt;/b&gt;にはタグ付き値に&lt;code&gt;service=twitter&lt;/code&gt;を定義して、TwitterによるTweet発生であることを記述しています。(ボクが使っているJudeではタグ付き値がクラスシンボルに表示されないようなので、コメントで定義しています。)&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-xK_EeCfPWNE/TZ4_sVyDfEI/AAAAAAAAAKk/0uL8R-K7Ptg/s1600/simple.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="140" src="http://1.bp.blogspot.com/-xK_EeCfPWNE/TZ4_sVyDfEI/AAAAAAAAAKk/0uL8R-K7Ptg/s400/simple.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;次は、(2)ManagedEntity/ServiceEntityを使う場合です。&lt;br /&gt;まず、PIM段階では以下のようにDomainResourceやDomainEventを使用していきます。具体的な実現方法はここでは記述しません。&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-nHl3snPzQ34/TZ4_uTJ6RrI/AAAAAAAAAKo/eAnh5lKfk48/s1600/pim.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="132" src="http://3.bp.blogspot.com/-nHl3snPzQ34/TZ4_uTJ6RrI/AAAAAAAAAKo/eAnh5lKfk48/s400/pim.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;これをPSM段階で具体的なサービスの活用を加えたものが以下のものです。&lt;b&gt;Tweet発生&lt;/b&gt;にServiceEntityを加え、&lt;b&gt;タスク起票&lt;/b&gt;と&lt;b&gt;タスク&lt;/b&gt;にManagedEntityを加えています。また、&lt;b&gt;Tweet発生&lt;/b&gt;にはタグ付き値に&lt;code&gt;service=twitter&lt;/code&gt;を定義して、TwitterによるTweet発生であることを記述しています。&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-7NTYKMLMIr4/TZ4_wP7GuFI/AAAAAAAAAKs/6LNd5xn0dUo/s1600/psm.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="187" src="http://1.bp.blogspot.com/-7NTYKMLMIr4/TZ4_wP7GuFI/AAAAAAAAAKs/6LNd5xn0dUo/s400/psm.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;この例はTwitterのツイートの取り込みを念頭においているものなので、「(1)ServiceResourceを使う」のが適している感じです。&lt;br /&gt;もちろん、アプリケーションの構想段階でドメインオブジェクトのどの部分を外部サービスのものを借りてくるか未定の場合には「(2)ManagedEntity/ServiceEntityを使う」記述方法が適しているでしょう。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7964484936470829118-3528551750648216408?l=modegramming.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://modegramming.blogspot.com/feeds/3528551750648216408/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://modegramming.blogspot.com/2011/04/blog-post_08.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/3528551750648216408'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/3528551750648216408'/><link rel='alternate' type='text/html' href='http://modegramming.blogspot.com/2011/04/blog-post_08.html' title='メタモデルとステレオタイプ'/><author><name>asami</name><uri>http://www.blogger.com/profile/12083671403528595185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_4HtJQwbXqEY/S4sSwhKz5fI/AAAAAAAAAFs/IvXW6ca5RGE/S220/profile.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-LUaF7dASDCY/TZ4_mGb_SyI/AAAAAAAAAKc/EqQmT0ruOR8/s72-c/MetaModel.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7964484936470829118.post-2917552304575197614</id><published>2011-04-07T07:15:00.000+09:00</published><updated>2011-04-07T07:15:01.085+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='simplemodeling'/><title type='text'>ドメインモデルとクラウドリソース</title><content type='html'>&lt;div&gt;&lt;p&gt;前回「ドメインオブジェクトとデータストアのマッピング」の検討は、SimpleModelingが元々定義しているドメインオブジェクトを検討対象にしています。つまり、クラウド登場前のドメインオブジェクトですね。伝統的なドメインモデルを、クラウドアプリケーションが扱わないといけない多種多様なデータストアにどのように格納管理するのかというのがテーマです。&lt;/p&gt;&lt;p&gt;それとは別の次元で、クラウド時代に入ってドメインモデルのスコープやドメインオブジェクトのモデル化対象をオーバーホールして見直す必要があると感じています。&lt;/p&gt;&lt;p&gt;クラウド時代以前のドメインモデルは基本的に自前でデータベースで管理するオブジェクトが中心で、システム外のオブジェクトはアクターという形で特別扱いして凌ぐ形になっています。&lt;/p&gt;&lt;p&gt;一方、クラウドアプリケーションの場合、複数のサービスをマッシュアップして構築するのが主流となるため、利用者のメンタルモデルに登場するオブジェクト、すなわちアプリケーションが扱うオブジェクトは、必ずしも自前のデータベースで管理するオブジェクトとは限りません。場合によっては、ほとんどが外部オブジェクトということになるでしょう。そのようなケースでこれらをアクターとしてモデル化するのは明らかに不適切です。&lt;/p&gt;&lt;p&gt;この問題に対応するには以下の2案が考えられます。&lt;/p&gt;&lt;ol&gt;&lt;li&gt; ドメインモデル(PIM段階)を概念モデル的な抽象度の高いモデルと位置づけ、設計時(PSM段階)に自前データベースか他サービス上のリソースかをモデル化する。&lt;br /&gt;&lt;/li&gt;&lt;li&gt; ドメインモデルの初期作成段階(PIM段階)からサービス上のリソースを専用のオブジェクトで表現する。&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;(PIM=Platform Independent Model=プラットフォーム独立モデル、PSM=Platform Specific Model=プラットフォーム固有モデル)&lt;/p&gt;&lt;p&gt;つまり、ドメインモデルを構成するオブジェクトとしてクラウド上のリソースを一級市民として扱うのか否かという問題ですね。&lt;/p&gt;&lt;p&gt;メタモデルとしての汎用性、拡張性という意味では前者(クラウドリソースをドメインモデルの一級市民として扱わない/PSM段階で導入)が美しいと思います。&lt;/p&gt;&lt;p&gt;しかし、クラウド時代にはクラウドサービスの活用がアプリケーションの中心的な関心事の一つであり、利用者自身も使用しているリソースとリソースを提供しているサービスの関係を意識するケースも多くなるため、PIM段階で自前データとクラウドリソースを明確に区別しておいたほうがなにかと得るものが多そうです。&lt;/p&gt;&lt;p&gt;また、設計実装との連続性という意味では、自前とサービス活用ではアプリケーションの構築のアプローチが異なってきます。PIMレベルのドメインモデルを構築した段階で、ざっくりとした工数見積もりができることも重要で、そういう意味でも自前オブジェクトとクラウドリソースをPIM段階で分離しておくのが実用的なアプローチであると考えています。&lt;/p&gt;&lt;p&gt;また、前者の美しいアプローチで起きそうな問題点として、自前リソースとクラウドリソースのアクセススピードの問題もあります。これは、複数のサービスの共通部分を抽出、汎化して、適切な抽象度のインタフェース経由で提供することができても、性能差がありすぎると事実上同じようには使えないという問題です。&lt;/p&gt;&lt;p&gt;たとえば、WebDavをExplore(Windows)やFinder(Mac)の配下に置いてExcelファイルなどをクリックで開いて使う使い方はとても便利ですが、UNIX shellの上からfindしたりとかそういう細かい使い方をしようとすると速度が遅すぎて心が折れてしまいます。後者のような使い方の場合、サービスに処理プログラム(クロージャ的な物)を投げてサービス側で処理を実行するエージェント的なアプローチ(レトロな言い方ではRJE(Remote Job Entry)かな)の方がより適切です。(WebDavは残念ながらこういう使い方はできませんが、これからのクラウドサービスではこういった利用方法への対応も重要な課題になると思います。)&lt;/p&gt;&lt;p&gt;また、細かいところでは故障頻度にも相当大きな差が出てきます。故障発生確率の大小で利用者への見せ方が変わってきます。加えて、障害発生時の可用性の問題も重要です。マッシュアップしている多数の外部サービスの一つが落ちただけで、自サービスがまるごと動かなくなるのは、アプリケーション的にはかなり恥ずかしいので、自サービスの根幹部と周縁部を切り分け適切に責務分割を行うことが必要です。&lt;/p&gt;&lt;p&gt;こういった要件の実現はアプリケーションアーキテクチャの根幹に関わってくるので、PSM段階から意識を始めるのはやや遅い感じで、PIM段階で意識の上に上げて起きたいところです。&lt;/p&gt;&lt;p&gt;今の所、以上のようなことを考えながら、机上で試行錯誤している状況です。たとえばドメインオブジェクトの種別DomainResourceを自前リソースと位置づけ、クラウド側のカウンターパートにCloudResourceやServiceResourceといったオブジェクトを新規に導入するのか、というようなことを検討しています。&lt;/p&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7964484936470829118-2917552304575197614?l=modegramming.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://modegramming.blogspot.com/feeds/2917552304575197614/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://modegramming.blogspot.com/2011/04/blog-post_07.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/2917552304575197614'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/2917552304575197614'/><link rel='alternate' type='text/html' href='http://modegramming.blogspot.com/2011/04/blog-post_07.html' title='ドメインモデルとクラウドリソース'/><author><name>asami</name><uri>http://www.blogger.com/profile/12083671403528595185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_4HtJQwbXqEY/S4sSwhKz5fI/AAAAAAAAAFs/IvXW6ca5RGE/S220/profile.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7964484936470829118.post-2551939878816853677</id><published>2011-04-06T09:18:00.000+09:00</published><updated>2011-04-06T09:18:07.710+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='simplemodeling'/><title type='text'>ドメインオブジェクトとデータストアのマッピング</title><content type='html'>&lt;div&gt;SimpleModelingと呼んでいるモデリング手法をクラウド向けに拡張する作業を行っています。&lt;br /&gt;その一つの柱がドメインモデルの拡張です。ドメインモデルの拡張の一つのアプローチは、オブジェクト種別ごとの実現方法の確立です。モデルから設計/実装へ落し込むときの指針が一つも目標ですが、最終的にはDSLコンパイラによる自動コーディングをターゲットにしています。&lt;br /&gt;SimpleModelingではドメインモデルを構成するオブジェクトに対して用途に応じた分類行い、プロファイルとして定義しています。代表的なオブジェクトは以下のものです。&lt;br /&gt;&lt;dl&gt;&lt;dt&gt;Actor&lt;br /&gt;&lt;/dt&gt;&lt;dd&gt;システム外に存在する(リアル)オブジェクトの代理オブジェクト。(例：利用者) &lt;/dd&gt;&lt;dt&gt;Event&lt;br /&gt;&lt;/dt&gt;&lt;dd&gt;システムで発生する出来事。 &lt;/dd&gt;&lt;dt&gt;Resource&lt;br /&gt;&lt;/dt&gt;&lt;dd&gt;システムが管理するリソース。 &lt;/dd&gt;&lt;dt&gt;Powertype&lt;br /&gt;&lt;/dt&gt;&lt;dd&gt;ドメインオブジェクトのパワータイプ。(実装時には区分コードなどで実現される) &lt;/dd&gt;&lt;dt&gt;Rule&lt;br /&gt;&lt;/dt&gt;&lt;dd&gt;ドメインで使用される規則。&lt;/dd&gt;&lt;/dl&gt;これらのオブジェクトの種別は、今までのソフトウェア開発でも有効ですが、クラウドアプリケーションではその価値がさらに高まります。というのは、クラウドアプリケーションではデータストアの選択が一つの大きな関心事になるからです。今までの企業システム、Webシステムでは大規模あるいは特殊要件がない限りはデータベースとしてRDBMSを一つだけ用いるということが普通です。このため、ドメインモデルとしてどのようなものを作るにしても、どうRDBMSに落し込むのかという設計へのマッピングが重要でした。しかし、クラウドアプリケーションでは複数のデータストアを用途に応じて使い分ける必要があります。一番大きいのがトランザクションやデータモデルの柔軟性というRDBMSの持つ特性が、スケーラビリティと相反する関係になる点です。この他にも半構造データの取り扱いや、分析処理向け性能特性など、必要に応じてデータストアを使い分けていく必要があります。このため、クラウドアプリケーションではRDBMS一刀流では用途が限定されてしまいます。用途に応じてデータストアを使い分けていく必要があります。&lt;br /&gt;&lt;h2&gt;データストアの種類&lt;/h2&gt;SimpleModelingのドメインモデル拡張での一つのアイデアは、ドメインモデルのオブジェクト種別ごとにデータストアとのマッピングの相性を定義することが有効ではないかということです。設計の指針にもなりますし、DSLコンパイラでのコード生成でも活用できます。&lt;br /&gt;データストアの種類として以下のものを想定しています。&lt;br /&gt;&lt;dl&gt;&lt;dt&gt;RDBMS&lt;br /&gt;&lt;/dt&gt;&lt;dd&gt;汎用的なデータストア。トランザクション。SQLによる高度な問合せ。複雑なデータ構造。スケーラビリティは低い。 &lt;/dd&gt;&lt;dt&gt;分散ディレクトリ&lt;br /&gt;&lt;/dt&gt;&lt;dd&gt;システムデータ管理向け。利用者情報などシステム管理データにアプリケーションが相乗りする使用方法。ほとんど参照でまれに更新されるデータに使用。トランザクション、SQL的な高度な問合せ、複雑なデータ構造はない。スケーラビリティは高い。 &lt;/dd&gt;&lt;dt&gt;分散キャッシュ&lt;br /&gt;&lt;/dt&gt;&lt;dd&gt;キャッシュデータの格納向け。ほとんど参照でまれに更新されるデータに使用。永続性はない。トランザクション、SQL的な高度な問合せ、複雑なデータ構造はない。スケーラビリティは高い。 &lt;/dd&gt;&lt;dt&gt;KVS&lt;br /&gt;&lt;/dt&gt;&lt;dd&gt;汎用的なデータストア。トランザクション、SQLによる高度な問合せ、複雑なデータ構造はない。スケーラビリティは高い。 &lt;/dd&gt;&lt;dt&gt;カラムナDB&lt;br /&gt;&lt;/dt&gt;&lt;dd&gt;分析処理向け。全件走査に強い。スケーラビリティは高い。トランザクション、SQLによる高度な問合せ、複雑なデータ構造については要調査。 &lt;/dd&gt;&lt;dt&gt;文書DB&lt;br /&gt;&lt;/dt&gt;&lt;dd&gt;半構造データの格納。その他の特性は要調査。 &lt;/dd&gt;&lt;dt&gt;プログラム埋込み&lt;br /&gt;&lt;/dt&gt;&lt;dd&gt;データをプログラムに埋込んで配備。高速動作。エラー要因、配備の複雑度を低減。データとアプリケーションのライフサイクルが一致する場合、特に有効。&lt;/dd&gt;&lt;/dl&gt;「プログラム埋込み」もデータストアの一種として考えています。データをプログラムに埋め込んで配備する手法は、従来のアプリケーション開発では邪道ですが、クラウド上では案外侮れない手法です。&lt;br /&gt;クラウドプラットフォームでは、プログラムがシステム上に多数存在する物理マシンに配備されるわけですが、この配備のメカニズムに乗って同時にデータも配備できるというメリットがあります。また、DSLコンパイラを使うと、プログラム開発とデータ定義を別々に行い、配備の段階で集約するといったことも可能になるので、データをプログラム内に埋め込むことのデメリットを緩和することができます。&lt;br /&gt;この他のデータストアとしてはCDN(Content Dlivery Network)が考えられますが、HTMLページなどの静的な成果物の配備が主な用途なので考慮の対象外にしています。(場合によっては対象に加えるかもしれません。)&lt;br /&gt;&lt;h2&gt;マッピング&lt;/h2&gt;ドメインオブジェクトとデータストアのマッピングは以下の図のものを考えています。用途を問わずすべてのデータをRDBMSを入れるというアプローチも当然あるわけですが、ここでは用途別により適したデータベースという視点で分類しています。&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-T5Q5hJS-z0Y/TZuwoQTsfjI/AAAAAAAAAKU/8uKScLl-ZnE/s1600/modelDatastorePolicy.png" imageanchor="1"&gt;&lt;img border="0" height="260" src="http://3.bp.blogspot.com/-T5Q5hJS-z0Y/TZuwoQTsfjI/AAAAAAAAAKU/8uKScLl-ZnE/s400/modelDatastorePolicy.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;詳細は後日。&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7964484936470829118-2551939878816853677?l=modegramming.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://modegramming.blogspot.com/feeds/2551939878816853677/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://modegramming.blogspot.com/2011/04/blog-post_06.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/2551939878816853677'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/2551939878816853677'/><link rel='alternate' type='text/html' href='http://modegramming.blogspot.com/2011/04/blog-post_06.html' title='ドメインオブジェクトとデータストアのマッピング'/><author><name>asami</name><uri>http://www.blogger.com/profile/12083671403528595185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_4HtJQwbXqEY/S4sSwhKz5fI/AAAAAAAAAFs/IvXW6ca5RGE/S220/profile.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-T5Q5hJS-z0Y/TZuwoQTsfjI/AAAAAAAAAKU/8uKScLl-ZnE/s72-c/modelDatastorePolicy.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7964484936470829118.post-730954158972121773</id><published>2011-04-04T08:22:00.001+09:00</published><updated>2011-04-06T09:04:27.442+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='simplemodeling'/><title type='text'>クラウドアプリケーションのモデリング考</title><content type='html'>オブジェクトモデリングは、元々の源流がシミュレーション向けプログラミング言語SIMULAにあることからも分かる通り、人間が認知する世界観を基本構成要素とするモデリング手法です。&lt;br /&gt;ビジネスモデリング、要求分析、システム分析、システム設計、実装(プログラミング)の各作業フェーズで同じモデル(オブジェクトとオブジェクト間の関係)を持ちまわることによってフェーズ間のインピーダンスミスマッチを低減することができ、要求モデルと実装の乖離を防ぎ、反復型の開発を可能にします。&lt;br /&gt;&lt;br /&gt;ただ、オブジェクトモデリングでモデリングの要件を全て満たせるのかというと、まだまだ力不足です。&lt;br /&gt;1つは、人間の認知モデルをベースにしているため、形式的な処理が難しいということです。オブジェクト間の関係は宣言的に記述することができますが、これらのオブジェクトによって構築される協調関係を宣言的に記述したり、形式的に取り扱って検証や合成、最適化といったことはできません。&lt;br /&gt;1つは、ビジネスモデリングから実装までモデルを持ちまわる事ができるのが問題領域の静的構造に限られること。動的モデルについては状態機械の範囲で部分的に持ちまわることができるだけです。これは、前述の「オブジェクトによって構築される協調関係を宣言的に記述できない」という問題に起因しています。&lt;br /&gt;&lt;br /&gt;このため、オブジェクトモデリングというと「問題領域の静的構造」に焦点が絞られることになりがちで、たとえば、これをどう実装するのかという切り口のドメイン駆動設計のような方向に技術が伸びていきます。&lt;br /&gt;それ自身は適切なアプローチですが、オブジェクトモデリング全体としてはシステムの振舞いをオブジェクト間の協調としてモデル化していく方向への拡張をしていかないと、汎用的なモデリング手法として適用範囲を広げることは難しいでしょう。&lt;br /&gt;&lt;br /&gt;振舞いモデルについては、(単なるお絵描きではない)データして活用可能なモデルを作成することができないとなると、モデリング作業そのものが無駄な作業といえなくもありません。&lt;br /&gt;「問題領域の静的構造」だけモデリングするのであれば、DOAのアプローチで十分ですし、軽量開発の場合ER図だけ用意すれば十分でしょう。&lt;br /&gt;そして、振舞いモデルをモデリングできないのであれば、ER図をかいた後、いきなりプログラミングが効率のよい開発手法となります。&lt;br /&gt;&lt;br /&gt;オブジェクトモデリングの柱の一つはユースケースです。ユースケースは「物語」によって利用者要求の暗黙知を抽出し、シナリオ分析技術によってオブジェクトの静的構造と協調を構築する技術とボクは理解しています。&lt;br /&gt;振舞いモデルを宣言的、形式的に扱えない弱点を持つオブジェクトモデリングですが、このユースケースがあることによって「問題領域の静的構造」だけのモデリング手法ではなく、総合的なモデリング手法として汎用的に使用できる技術体系となっているといえます。&lt;br /&gt;ただし、このユースケースはかなり難しい技術で、うまく使いこなせないのであれば背伸びしてオブジェクトモデリングをするより、ER図＋プログラミングの方が効率よく精度の高いシステム構築ができるでしょう。&lt;br /&gt;&lt;br /&gt;オブジェクトモデリングの現状分析はこんな感じですが、これをクラウドアプリケーションに対して、どう適用していくのかというのが、ここ数年考えてきたことです。&lt;br /&gt;まだまだ、試行錯誤の段階ですがいくつか切り口があります。&lt;br /&gt;&lt;br /&gt;1つは、手堅いモデリング技術であるドメインモデルをクラウドアプリケーション向けにチューンするアプローチ。&lt;br /&gt;ソーシャルグラフをどのようにモデル化するのかというアナリシスパターン的な切り口、モデル構造の雛形を定めるメタモデルやプロファイルの切り口、クラウド的なトランザクションやBigDataといったプラットフォームに落し込む手法の整備が必要です。&lt;br /&gt;&lt;br /&gt;また、ユースケースをクラウドアプリケーションに適用する手法についても整備が必要です。&lt;br /&gt;従来型のユースケースは、利用者とシステムのショートトランザクション粒度のインタラクションがターゲットでしたが、クラウド環境では非同期処理、並行処理、ロングトランザクションといった要因が重要になってくるので、そのままの形では適用が難しいでしょう。&lt;br /&gt;また、UX(User Experience)技術の興隆によって、ユースケースの適用範囲も変わってきます。&lt;br /&gt;従来のユースケースの運用では、ドメインモデルとの接続箇所が曖昧で、方法論としての整備も遅れていたので、この点の充実も併せて必要でしょう。&lt;br /&gt;&lt;br /&gt;加えて、システムの振舞いモデル(オブジェクト間の協調モデル)に対してのアプローチを考える必要があります。&lt;br /&gt;ここは元々従来もうまくいっていないところなので、クラウドアプリケーションでいきなり解決することは考えられません。&lt;br /&gt;とはいえ、非同期、並列、分散がより重要なパーツとなってくるクラウドアプリケーションなので、何らかの対応策は考えたいところです。&lt;br /&gt;&lt;br /&gt;アプリケーションの振舞いのアーキテクチャの側面では、要求駆動からイベント駆動への移行も重要です。&lt;br /&gt;要求駆動は、たとえば画面にフォームを入力しエンターキーを押すとその延長で同期型でリクエストが発行されSQLが実行され結果が返されるといったアーキテクチャです。&lt;br /&gt;それに対して、イベント駆動はクラウド上で発生する様々なイベントをアプリケーションがイベントハンドラで受けとり、都度小さな処理を自身のリソースに対して行ったり、協調動作する相方にメッセージを投げたりして処理を進めていくアーキテクチャです。&lt;br /&gt;前者はシェルからCLIで動作させる単発のコマンド的な振舞い、後者は各種イベントを割り込みハンドラで拾いながら動作する制御システム的な振舞いです。&lt;br /&gt;アプリケーションの振舞いが相当複雑化することが容易に推測できます。&lt;br /&gt;&lt;br /&gt;大規模データへの対応では、DFD(データフロー図)的なアプローチが再び表舞台に出てきそうです。&lt;br /&gt;エンタープライズ系の開発ではDFDは今でもよく利用されていると思いますが、実装時に手組みプログラミングになるのでその効果は限定的です。&lt;br /&gt;クラウドアプリケーションで事情が変わってくるのは、大規模データの扱いにおいて手組みのプログラミングではなく、DFD的なモデルからHadoopのような大規模データ処理向けのコードを自動生成するアプローチが実用化されるかもしれないという点によります。&lt;br /&gt;ここは、単なる転記を超えたプログラムが必要となるところで、手組みのプログラミングでは、Hadoopのようなフレームワーク向けに合わせる接合部のコーディングが煩雑、最適化やデバッグが難しいという問題があり、これは自動生成のコストをかけても十分に実用化できそうです。&lt;br /&gt;この方面では、SQL的、関係演算的な切り口の言語で大規模データを扱うというアプローチもあり、動向が注目されます。&lt;br /&gt;&lt;br /&gt;つらつらと書いてきましたが、現在は、こういった論点についてScala DSLモデルコンパイラSimpleModelerとサービスマッシュアップフレームワークg3を開発しながら試行錯誤を続けています。&lt;br /&gt;ちょうど立ち止まっておさらいするのによいタイミングだと思うので、途中結果をブログにまとめよう思います。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7964484936470829118-730954158972121773?l=modegramming.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://modegramming.blogspot.com/feeds/730954158972121773/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://modegramming.blogspot.com/2011/04/blog-post.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/730954158972121773'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/730954158972121773'/><link rel='alternate' type='text/html' href='http://modegramming.blogspot.com/2011/04/blog-post.html' title='クラウドアプリケーションのモデリング考'/><author><name>asami</name><uri>http://www.blogger.com/profile/12083671403528595185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_4HtJQwbXqEY/S4sSwhKz5fI/AAAAAAAAAFs/IvXW6ca5RGE/S220/profile.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7964484936470829118.post-6027831832106726083</id><published>2011-03-31T08:29:00.001+09:00</published><updated>2011-04-06T09:03:47.863+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='g3'/><category scheme='http://www.blogger.com/atom/ns#' term='akakusa'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>Asakusa Scala DSL</title><content type='html'>基幹バッチをターゲットにしたHadoopフレームワークAsakusaのScala DSLにトライしています。&lt;br /&gt;&lt;br /&gt;DSLの素案が固まってきたので、SimpleModelerに組み込んでみました。&lt;br /&gt;&lt;br /&gt;DSLを検証するために使用したモデルは、Asakusaのホワイトペーパーにある以下の図7です。&lt;br /&gt;比較的シンプルですが、基幹バッチのデーターフローをモデルとして記述しています。&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-4NgaLqB-b94/TZO6BRwyqaI/AAAAAAAAAKM/O0fNBHEzpbg/s1600/figure7.png" imageanchor="1" style=""&gt;&lt;img border="0" height="231" width="320" src="http://1.bp.blogspot.com/-4NgaLqB-b94/TZO6BRwyqaI/AAAAAAAAAKM/O0fNBHEzpbg/s320/figure7.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Asakusaでは、このようなデータフローをJava DSLで記述するわけですが、ここにScala DSLを用いるとより簡潔に記述できるのではないかと考えているわけです。&lt;br /&gt;&lt;br /&gt;このデーターフローをScala DSLで記述したものが以下の&lt;b&gt;会計処理バッチ.scala&lt;/b&gt;です。&lt;br /&gt;具体的な説明は追々していこうと思いますが、ここではぱっと見た感じ、簡潔に明快な形で記述できているような印象を持って頂けるとうれしいと思います。&lt;br /&gt;&lt;br /&gt;このScala DSLの設計のポイントはScalaの型パラメータを使って、型安全にモデルを記述している点です。&lt;br /&gt;少しの記述ミスでもコンパイラがエラーで教えてくれる点が、Scalaのような静的型付け言語をDSLのホスト言語として使用するメリットですが、型パラメータを使用することでこの長所を最大限に活かすことができます。&lt;br /&gt;&lt;br /&gt;&lt;pre class="java" name="code"&gt;package sample&lt;br /&gt;&lt;br /&gt;import org.simplemodeling.dsl.domain._&lt;br /&gt;import org.simplemodeling.dsl.flow._&lt;br /&gt;&lt;br /&gt;class 仕入明細データ extends DomainResource&lt;br /&gt;class 仕入返品データ extends DomainResource&lt;br /&gt;class 費用振替データ extends DomainResource&lt;br /&gt;class 売価変更データ extends DomainResource&lt;br /&gt;&lt;br /&gt;class 修正在庫振替TRN extends DataSet&lt;br /&gt;class 修正未収収益TRN extends DataSet&lt;br /&gt;class 修正在庫移動TRN extends DataSet&lt;br /&gt;class 未払計上TRN extends DataSet&lt;br /&gt;&lt;br /&gt;class 仕入TRN extends DataSet&lt;br /&gt;class 在庫振替TRN extends DataSet&lt;br /&gt;class 在庫移動TRN extends DataSet&lt;br /&gt;class 未収収益TRN extends DataSet&lt;br /&gt;&lt;br /&gt;class 計上済仕入TRN extends DataSet&lt;br /&gt;class 計上済未収収益TRN extends DataSet&lt;br /&gt;class 計上済未払費用TRN extends DataSet&lt;br /&gt;class 更新済買掛残高TRN extends DataSet&lt;br /&gt;&lt;br /&gt;class 請求エラーTRN extends DataSet&lt;br /&gt;class 支払不可消込TRN extends DataSet&lt;br /&gt;class 支払可消込TRN extends DataSet&lt;br /&gt;class 照合済支払費用TRN extends DataSet&lt;br /&gt;class 照合済未収収益TRN extends DataSet&lt;br /&gt;class 照合済仕入TRN extends DataSet&lt;br /&gt;class 照合済請求TRN extends DataSet&lt;br /&gt;&lt;br /&gt;class 仕入データ extends DataSource4[仕入明細データ, 仕入返品データ,&lt;br /&gt;                                     費用振替データ, 売価変更データ]&lt;br /&gt;class 修正データ extends DataSource4[修正在庫振替TRN, 修正未収収益TRN,&lt;br /&gt;                                     修正在庫移動TRN, 未払計上TRN]&lt;br /&gt;class 売価変更在庫変更TRN extends DataSet&lt;br /&gt;class 仕入データTRN extends DataSource4[仕入TRN, 在庫振替TRN,&lt;br /&gt;                                        在庫移動TRN, 未収収益TRN]&lt;br /&gt;class 残高更新TRN extends DataSource4[計上済仕入TRN, 計上済未収収益TRN,&lt;br /&gt;                                      計上済未払費用TRN, 更新済買掛残高TRN]&lt;br /&gt;class 請求TRN extends DataSet&lt;br /&gt;class 会計データTRN extends DataSource7[請求エラーTRN, 支払不可消込TRN, 支払可消込TRN,&lt;br /&gt;                                        照合済支払費用TRN, 照合済未収収益TRN,&lt;br /&gt;                                        照合済仕入TRN, 照合済請求TRN]&lt;br /&gt;&lt;br /&gt;case class 仕入データ取り込み(cout: Port[売価変更在庫変更TRN]) extends Operator12[仕入データ, 仕入データTRN, 売価変更在庫変更TRN](cout)&lt;br /&gt;case class 残高更新(cin: Port[修正データ]) extends Operator21[仕入データTRN, 修正データ, 残高更新TRN](cin)&lt;br /&gt;case class 照合処理(cin: Port[請求TRN]) extends Operator21[残高更新TRN, 請求TRN, 会計データTRN](cin)&lt;br /&gt;&lt;br /&gt;// 図7 改善された会計処理バッチの処理フロー&lt;br /&gt;case class 会計処理バッチ extends Flow32[仕入データ, 修正データ, 請求TRN,&lt;br /&gt;                                    会計データTRN, 売価変更在庫変更TRN] {&lt;br /&gt;  start op12(仕入データ取り込み(out2)) op21(残高更新(in2)) op21(照合処理(in3)) end&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;このScala DSLからSimpleModelerで生成したフロー図が以下のものです。&lt;br /&gt;データフローの概要をつかむのに十分な図が得られていると思います。&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-rSr_bS3uoyA/TZOw3HH3lcI/AAAAAAAAAKE/tiwqkDIRZRY/s1600/FlowMachineDiagram%25E4%25BC%259A%25E8%25A8%2588%25E5%2587%25A6%25E7%2590%2586%25E3%2583%2590%25E3%2583%2583%25E3%2583%2581%25E4%25BC%259A%25E8%25A8%2588%25E5%2587%25A6%25E7%2590%2586%25E3%2583%2590%25E3%2583%2583%25E3%2583%2581.png" imageanchor="1" style=""&gt;&lt;img border="0" height="154" width="320" src="http://1.bp.blogspot.com/-rSr_bS3uoyA/TZOw3HH3lcI/AAAAAAAAAKE/tiwqkDIRZRY/s320/FlowMachineDiagram%25E4%25BC%259A%25E8%25A8%2588%25E5%2587%25A6%25E7%2590%2586%25E3%2583%2590%25E3%2583%2583%25E3%2583%2581%25E4%25BC%259A%25E8%25A8%2588%25E5%2587%25A6%25E7%2590%2586%25E3%2583%2590%25E3%2583%2583%25E3%2583%2581.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;このような図が生成できるということは、SimpleModelerの内部でデータフローのグラフ構造が適切に構築できたことを示しています。&lt;br /&gt;このグラフ構造を使って、モデル検証を行ったり、モデルのクロスリファレンスを作成したり、さらにAsakusa Java DSLの自動生成を行うことが可能のはずです。&lt;br /&gt;&lt;br /&gt;Asakusaでは、各種DSL向けにAsakusa Hadoopコンパイラの内部モデル(Asakusa IR?)が提供されるとのことなので、それを待ってAsakusa Hadoopコンパイラの連携部を作成していく予定です。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7964484936470829118-6027831832106726083?l=modegramming.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://modegramming.blogspot.com/feeds/6027831832106726083/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://modegramming.blogspot.com/2011/03/asakusa-scala-dsl.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/6027831832106726083'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/6027831832106726083'/><link rel='alternate' type='text/html' href='http://modegramming.blogspot.com/2011/03/asakusa-scala-dsl.html' title='Asakusa Scala DSL'/><author><name>asami</name><uri>http://www.blogger.com/profile/12083671403528595185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_4HtJQwbXqEY/S4sSwhKz5fI/AAAAAAAAAFs/IvXW6ca5RGE/S220/profile.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-4NgaLqB-b94/TZO6BRwyqaI/AAAAAAAAAKM/O0fNBHEzpbg/s72-c/figure7.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7964484936470829118.post-4740739637961395987</id><published>2011-02-28T06:01:00.001+09:00</published><updated>2011-04-06T09:03:14.373+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rest'/><category scheme='http://www.blogger.com/atom/ns#' term='g3'/><title type='text'>Access-Control-Allow-Origin</title><content type='html'>WebブラウザからRESTをアクセスするプログラムを開発するときに、困るのがクロスオリジンの問題。&lt;br /&gt;Webページ上で動作するJavaScriptプログラムは、Webページをダウンロードしたサイトにしかアクセスができない、というアレです。&lt;br /&gt;&lt;br /&gt;プログラム開発中では、作ったプログラムをわざわざサーバーに上げるといったような作業が必要となるため、とても不便です。&lt;br /&gt;また、運用時でもREST APIを一般に公開する場合には、大きな制約になります。&lt;br /&gt;&lt;br /&gt;この問題は従来JSONPで回避してきましたが、最近はAccess-Control-Allow-Originという手法があるのを知り、g3に実装してみました。&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.w3.org/TR/cors/"&gt;Cross-Origin Resource Sharing&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Access-Control-Allow-Originはブラウザ側でのクロスオリジンの選択をするために必要な情報を、HTTPのヘッダにクロスオリジン情報を付加するものです。&lt;br /&gt;ブラウザは、従来はクロスオリジンであればすべて拒否していたのを、ヘッダに許可情報がある場合はクロスオリジンを許可するという動きになります。&lt;br /&gt;&lt;br /&gt;具体的には、GET, POST, PUT, DELETEではリプライのヘッダにAccess-Control-Allow-Originヘッダを設定します。&lt;br /&gt;&lt;br /&gt;Servletの該当箇所は以下のようになります。(g3の実装なのでScalaです。)&lt;br /&gt;&lt;br /&gt;&lt;pre class="java" name="code"&gt;resp.setHeader("Access-Control-Allow-Origin", "*")&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;GET, POST, PUT, DELETEにAccess-Control-Allow-Originをつけるだけでよいと勘違いしていて、ちょっとはまったのですが、実はOPTIONSでリソースアクセスに対するクロスオリジン定義を返さないといけないのですね。&lt;br /&gt;以下の情報をヘッダに設定します。&lt;br /&gt;&lt;br /&gt;&lt;dl&gt;&lt;dt&gt;Access-Control-Allow-Origin&lt;/dt&gt;&lt;dd&gt;クロスオリジンを許すURL。すべて許す場合は「*」。&lt;/dd&gt;&lt;dt&gt;Access-Control-Allow-Methods&lt;/dt&gt;&lt;dd&gt;Access-Control-Request-Methodに指定されたメソッドを返すのが丁寧っぽいですが、公開してるメソッドをすべてを毎回返すようにしても大丈夫のようです。&lt;/dd&gt;&lt;dt&gt;Access-Control-Allow-Header&lt;/dt&gt;&lt;dd&gt;Access-Control-Request-Headersで指定されている文字列を返します。ブラウザがチェック用に使っているみたいです。&lt;/dd&gt;&lt;dt&gt;Access-Control-Max-Age&lt;/dt&gt;&lt;dd&gt;このOPTIONSの設定の有効時間。この時間が過ぎると再度OPTIONSでクロスオリジン定義を取りにきます。&lt;/dd&gt; &lt;/dl&gt;&lt;br /&gt;Servlet該当箇所は以下のようになります。&lt;br /&gt;&lt;br /&gt;&lt;pre class="java" name="code"&gt;resp.setHeader("Access-Control-Allow-Origin", origin)&lt;br /&gt;      resp.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, DELETE, OPTIONS")&lt;br /&gt;      resp.setHeader("Access-Control-Allow-Headers", req.getHeader("Access-Control-Request-Headers"))&lt;br /&gt;      resp.setHeader("Access-Control-Max-Age", accessControlMaxAge.toString)&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7964484936470829118-4740739637961395987?l=modegramming.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://modegramming.blogspot.com/feeds/4740739637961395987/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://modegramming.blogspot.com/2011/02/access-control-allow-origin.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/4740739637961395987'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/4740739637961395987'/><link rel='alternate' type='text/html' href='http://modegramming.blogspot.com/2011/02/access-control-allow-origin.html' title='Access-Control-Allow-Origin'/><author><name>asami</name><uri>http://www.blogger.com/profile/12083671403528595185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_4HtJQwbXqEY/S4sSwhKz5fI/AAAAAAAAAFs/IvXW6ca5RGE/S220/profile.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7964484936470829118.post-4931915140439130335</id><published>2011-01-31T08:53:00.000+09:00</published><updated>2011-01-31T08:53:43.277+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='websocket'/><category scheme='http://www.blogger.com/atom/ns#' term='g3'/><title type='text'>Web Socketなど</title><content type='html'>&lt;div&gt;とある事情があって、g3にHTML5のWeb SocketやServer-Sent Event機能を追加してみました。&lt;br /&gt;Web SocketはJettyの機能を利用しています。&lt;/div&gt;&lt;br /&gt;&lt;div&gt;今回使ったWeb SocketとServer-Sent Eventを使ったg3アプリケーションは以下のものです。&lt;/div&gt;&lt;br /&gt;&lt;pre class="java" name="code"&gt;class Html5Service extends G3Application {&lt;br /&gt;  port("/") html(&amp;lt;p&amp;gt;OK&amp;lt;/p&amp;gt;)&lt;br /&gt;&lt;br /&gt;  port("/sse") agent {&lt;br /&gt;    case _ =&amp;gt; {&lt;br /&gt;      EventStream(System.currentTimeMillis.toString, 1000)&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  port("/ws/chat") agent {&lt;br /&gt;    case msg: Post =&amp;gt; {&lt;br /&gt;      new Post("/chat", msg.content)&lt;br /&gt;    }&lt;br /&gt;  } invoke("wschat")&lt;br /&gt;&lt;br /&gt;  websocket('wschat, "/chat")&lt;br /&gt;  websocket('wstimer, "/timer")&lt;br /&gt;&lt;br /&gt;  timer("") agent {&lt;br /&gt;    case msg: Post =&amp;gt; {&lt;br /&gt;      Post("/timer", "Time: " + System.currentTimeMillis)(&lt;br /&gt;    }&lt;br /&gt;  } invoke("wstimer")&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;動作概念図はこんな感じ。&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_4HtJQwbXqEY/TUXhvjO-NjI/AAAAAAAAAJ4/fIVWgKKhKwk/s1600/g3websockets.png" imageanchor="1" style=""&gt;&lt;img border="0" height="288" width="320" src="http://4.bp.blogspot.com/_4HtJQwbXqEY/TUXhvjO-NjI/AAAAAAAAAJ4/fIVWgKKhKwk/s320/g3websockets.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;「/」(e.g. http://example.com/demo/)にアクセスが来ると「OK」が表示されます。これは動作確認のため。&lt;br /&gt;&lt;br /&gt;「/sse」(e.g. http://example.com/demo/sse)にアクセスが来ると、以下のようなServer-Sent Eventを返します。MIMEタイプはtext/event-streamです。&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;retry: 1000&lt;br /&gt;&lt;br /&gt;data: 1292615603413&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;実現方式は簡単で、新たにtext/event-streamなメッセージEventStreamを追加しました。Server-Sent Eventの仕様はシンプルなので、サーバー側の仕組みもいたってシンプルです。&lt;br /&gt;ただ、残念なことに現在の所、ブラウザが想定しているフォーマットと少しずれているのか、Safariではうまく動きませんでした。仕組みは簡単なので、原因が分かれば修正も簡単にできるでしょう。&lt;br /&gt;&lt;br /&gt;「/ws/chat」は、チャットの入力となるHttpのURIです。g3のWebSocketチャネル「wschat」を経由して、WebSocketのポート「/ws/chat」にデータを出力しています。&lt;br /&gt;&lt;br /&gt;WebSocketのポートとして、「/ws/chat」と「/ws/timer」が公開されています。「/ws/chat」は前述のように、HTMLのURIの「/ws/chat」からループバックして接続されています。このループバックによってチャット機能を実現しています。&lt;br /&gt;&lt;br /&gt;「/ws/timer」は、タイマーからg3のWebSocketチャネル「wstimer」を経由して、タイマーからの入力を受取り、WebSocketに送信しています。&lt;br /&gt;&lt;br /&gt;g3は、RESTのセマンティクスを軸にコンポーネントを疎結合して、非同期メッセージング、イベント駆動で動作させるフレームワークですが、WebSocketやServer-Sent Eventもシームレスに統合できることが確認できました。&lt;br /&gt;上記のプログラムは、チャネル間を配線しただけの簡単なものですが、アプリケーションロジックをチャネルのエージェントとして配備することでより複雑な処理ができるようになります。&lt;br /&gt;たとえば、一定時間ごとにEvernoteにアクセスして、取得した結果をWeb SocketやServer-Sent Eventでプッシュ配信する、というようなアプリケーションを簡単に作れるでしょう。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7964484936470829118-4931915140439130335?l=modegramming.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://modegramming.blogspot.com/feeds/4931915140439130335/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://modegramming.blogspot.com/2011/01/web-socket.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/4931915140439130335'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/4931915140439130335'/><link rel='alternate' type='text/html' href='http://modegramming.blogspot.com/2011/01/web-socket.html' title='Web Socketなど'/><author><name>asami</name><uri>http://www.blogger.com/profile/12083671403528595185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_4HtJQwbXqEY/S4sSwhKz5fI/AAAAAAAAAFs/IvXW6ca5RGE/S220/profile.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_4HtJQwbXqEY/TUXhvjO-NjI/AAAAAAAAAJ4/fIVWgKKhKwk/s72-c/g3websockets.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7964484936470829118.post-841025204393310571</id><published>2010-12-15T18:21:00.001+09:00</published><updated>2010-12-15T18:21:41.935+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='architecture'/><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>Androidのアーキテクチャ</title><content type='html'>このところAndroidに集中して取り組んでいるのですが、その作業の中で、Androidアプリのアーキテクチャとして使えそうなものが見えてきたのでメモしておきます。&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_4HtJQwbXqEY/TQiB2HoMbxI/AAAAAAAAAJw/YRx783XPsRI/s1600/AndroidArch.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="217" src="http://3.bp.blogspot.com/_4HtJQwbXqEY/TQiB2HoMbxI/AAAAAAAAAJw/YRx783XPsRI/s400/AndroidArch.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;図で赤くなっているオブジェクトは、Androidの基本クラスでAndroid OS上で特別な機能を担うものです。これらのオブジェクトをベースとして、どのようなオブジェクト群を追加し、どのような責務配分をして全体をバランスさせるのかという点が論点となります。&lt;br /&gt;&lt;br /&gt;このアーキテクチャでは、ControllerとModelという2つのクラスを導入して、上記の配線でActivity、Handler、Thread、Serviceを結びつけています。&lt;br /&gt;ここで注意が必要なのは、ControllerとModelという名前。他に良い名前がないのでControllerとModelという名前を付けていますが、気持ちとしては(MVCではなく)PACアーキテクチャパターンのControlとAbstractionを意図しています。&lt;br /&gt;UIデバイス周りの低レベルイベントはActivity(PACのPresentation)で処理し、Controller(PACのC)はUX領域のセマンティックイベントの処理を行います。&lt;br /&gt;一方Serviceの方は、利用者以外のアクター、すなわち外部サービスや時間といった外部事象からのイベント処理を行います。&lt;br /&gt;Modelは、アプリケーションロジックを記述します。データベースやファイルそしてDriver経由で外部サービスの呼出しを行います。&lt;br /&gt;外部との連携はDriverとReceiverの2つのオブジェクトを用います。Driverは従来的なPull型の連携を行うドライバです。Receiverはクラウド的なプッシュ型連携を受け取るドライバです。&lt;br /&gt;&lt;br /&gt;Androidは、ちょっと本格的なアプリケーションになると内部的には非同期メッセージを駆使したプログラミングモデルになってくるので、そのあたりをどうさばくのかというがアーキテクチャを考える上での軸の一つとなります。&lt;br /&gt;Real-Time UML的にはタスク設計的なことも必要になります。&lt;br /&gt;&lt;br /&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;この図では直接見えてきませんが、このアーキテクチャは、Androidのスレッド構造にも配慮しています。肝になるのが、GUI用スレッドがGUIリソースを専有している点。Handlerが鍵となるオブジェクトです。&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;また、クラウドとスマートデバイスを統合したトータルでのアプリケーションアーキテクチャとの中でも機能するアーキテクチャである点も重要です。&lt;br /&gt;この点は、非同期メッセージをプログラミングモデルの基盤に据えることで要件を満たせると考えており、その点をアーキテクチャに盛り込んでいます。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7964484936470829118-841025204393310571?l=modegramming.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://modegramming.blogspot.com/feeds/841025204393310571/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://modegramming.blogspot.com/2010/12/android.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/841025204393310571'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7964484936470829118/posts/default/841025204393310571'/><link rel='alternate' type='text/html' href='http://modegramming.blogspot.com/2010/12/android.html' title='Androidのアーキテクチャ'/><author><name>asami</name><uri>http://www.blogger.com/profile/12083671403528595185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_4HtJQwbXqEY/S4sSwhKz5fI/AAAAAAAAAFs/IvXW6ca5RGE/S220/profile.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_4HtJQwbXqEY/TQiB2HoMbxI/AAAAAAAAAJw/YRx783XPsRI/s72-c/AndroidArch.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7964484936470829118.post-6106433781984901812</id><published>2010-11-27T10:00:00.040+09:00</published><updated>2010-11-27T10:00:01.535+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='v
