« 2011年03月 | メイン | 2011年05月 »

2011年04月 アーカイブ

2011年04月10日

StrategyパターンとVisitorパターンの使い分けに関する考察(2)

StrategyパターンとVisitorパターンの応用例として、簡単な引力モデルのシミュレーションを作ってみる。引力の計算方法は外部クラスに存在させ、既存クラスを変更せずに追加/変更可能にする。
なるべく簡単にするため、次のような制限をつける。
・全物体の質量は同じ
・空間は2次元
・引力は2物体間の距離だけで決まる

まず、Strategyパターンを応用する例を考える。
引力の計算方法についてStrategyパターンを適用し、クラス構成は、次のようにする。

class diagram

PhysicalObjectクラスの階層(緑部分)が物体の位置や速度を持ち、GravityStrategyクラス/インターフェースの階層(水色)が引力の計算処理を持つ。抽象レベルでPhysicalObjectがGravityStrategyに関連づけるため、PhysicalObjectの基底クラスがGravitystrategyへの参照を持つ。
NormalGravityは距離の2乗に反比例する引力、Repulsionは距離の2乗に反比例する斥力、NoGravityは引力なしである。

GravityStrategyが定義するメソッドは、計算結果を返すようにする方が自然だが、今回の例では、そのまま計算結果をPhysicalObjectに反映するようにしている。これは、Visitorとの類似性を追究する目的のため、そのようにした。その為、 PhysicalObjectの値を更新する為のaccessor(VelocityControllerインターフェース)が必要になっている。

Strategyパターンとして、そういう実現方法は許されるのかという問題があるが、一般に計算結果が1つの値とは限らないし、Strategyに委譲する処理が複雑になるほど、戻り側で必要な値が増える可能性があるし、出力する値の個数が決まっていると拡張する範囲が限られてしまう。
また、入力としてオブジェクト丸ごとでなく、最低限のパラメーターだけを渡す方がいいという考え方もあるが、やはりそのパラメーターの数が決まっていると拡張性が制限されてしまう可能性がある。
それに、入力のデータ型を新たに定義せずに委譲元のクラスそのものとするのであれば、出力のデータ型についてだけ、戻り値を格納できる新たなデータ型を定義するのはすっきりしないし、一般にStrategyの計算結果は中間データなので、委譲元のクラスには格納できない。
よって、Strategyへの入力を委譲元のオブジェクトそのものとし、併せてそれへのaccessorを渡すことにより、計算結果の反映までをStrategyに委譲する方法は、1つの妥当な方法だと考えられる。
Strategyパターンの本質は、クラスの一部の処理を差し替え可能な形で別のクラス(Strategy)に委譲することにより、既存クラスを変更せずに処理を追加できるようにすることにあるので、Strategyクラスに対して既存クラスを隠蔽することは優先されないと、筆者は考える。

Strategyを呼び出すのはPhysicalObjectクラスのupdateVelocityメソッドで、このメソッドは存在する自分自身以外の全ての物体についてStrategyを呼び出すことにより、他の物体からの引力作用を自身の速度に反映させる。
物体の形状は、PhysicalObjectが、形状そのものではなく、形状の描画方法として定義する。抽象的なPhysicalObjectは形状を持たないので、具体的な描画方法はPhysicalObjectの各サブクラスが持つ。

ついでに、描画時の色をStrategyパターンで切り替えられるようにもしてみる。
物体の色は、物理的特徴の1つとしてPhysicalObjectに持ち、ColorStrategyによって標準色から変更されるとする。ColorStrategyがnullなら、標準色とする。

Strategyパターンの実装として、Strategyを無設定にすることが許されるかという問題があるが、よくわからないので、そういう問題があることをメモしておく目的で、ここでは無設定を許すとする。
おそらく、デフォルトの処理を本体に持つかStrategyに持つかという問題に関係していると思う。デフォルトの処理が原始的で変更される可能性が無く、本体にあって自然なら、Strategyとしてnullが許されるのではないだろうか。
また、Strategyが計算結果を返すなら、Strategyがnullな状態を許すと、それに対応する計算結果と同じ型の値が必要になるので、違和感があるような気がする。
GravityStrategyの方は、無重力とは引力作用が無いということではなく、ゼロの引力が働いているものとして扱うため、明示的にクラス化している。

以上の方針によって実装したのが、次のリンク先のページのJavaアプレットである。(ソースコードへのリンクもあり)
・StrategySample2のアプレットとソースコードのページ
フィールド上をクリックすると、何らかの物体が置かれる。
"Disc", "Wired Star", "Star"のいずれかのボタンを押すと、クリックして置かれる物体が切り替わる。
"Switch gravity strategy"を押すと、次に置かれる物体の引力のルールが切り替わる。
フィールドは、表示されている領域の3x3倍の大きさがあり、それより外に出た物体は削除される。
標準(デフォルト)の引力と色は次の通り。

無指定時の引力無指定時の色
Disc引力水色
Wired Star無重力マゼンタ
Star斥力黄色

あとはソースコード参照。

次のエントリーでは、大体同じものをVisitorパターンで作ってみる。
(続く)

続きを読む "StrategyパターンとVisitorパターンの使い分けに関する考察(2)" »

2011年04月17日

StrategyパターンとVisitorパターンの使い分けに関する考察(3)

前のエントリーでStrategyパターンで作った引力モデルのシミュレーションとほぼ同じものを、今度はVisitorパターンで作ってみる。


class diagram

Strategyパターンの場合との全体的な構造上の違いとして、本体のクラスに切替可能な処理(またはアルゴリズム)への関連が無く、処理を実装するクラスから本体のクラス階層への関連がある。具体的には、PhysicalObjectクラスにVisitorのメンバが無く、Visitorの具象クラスから本体の具象クラスへの依存がある。

切替可能な処理の構造の違いとしては、Strategyパターンでは本体の具象クラス毎の既定の処理をStrategyでなく本体側に入れることが可能であったのに対して、VisitorパターンではそれらをVisitor側に定義する必要がある。もし本体側に実装しても、それを呼び出す仕組みが必要になるので、Visitor側にクラスを定義するのは避けられない。
また、Strategyパターンでは処理が無い場合は無処理のStrategyを定義する必要があった(特にStrategyが値を返す場合)が、Visitorパターンでは無処理ならVisitorを定義する必要が無い。
具体的には、各PhysicalObjectの標準の処理の実装のために、DefaultGravity, DefaultColorizerというクラスを定義しており、無重力の場合は引力計算の処理の必要が無いので、NoGravityApplierはのようなクラスを定義していない。

なお、ColorVisitorのサブクラスにて各PhysicalObjectの標準色を使う場合があるため、
標準色の設定処理はColorVisitorクラスに実装するようにし、DefaultColorizerは、ColorVisitorをそのまま引き継ぐ、インスタンス生成可能にするためだけの空のクラスとしている。ColorVisitorを抽象クラスでなく具象クラスにすればDefaultColorizerクラスが不要になるように思えるが、そうすると、ColorVisitorが標準色の設定の役割を兼ね、ColorVisitorのサブクラスが標準色の設定の役割を持つColorVisitorとして振る舞えることになってしまい、いわゆるリスコフの置換原則に反してしまうので、好ましくない。

以上の方針で実装したのが、下のリンク先のページのJavaアプレットである。(ソースコードへのリンクもあり)
・VisitorSample2のアプレットとソースコードのページ

StrategyパターンのサンプルではボタンによるStrategyの切替がそれ以後に追加される物体のみに有効になるのに対し、Visitorパターンのサンプルでは、フィールド上にある全ての物体に対して切り替わる。
WiredStarについては、同じVisitorでもvisit先の具象クラスによって処理を変更する例として、全てのGravityVisitorのvisit()を空にし、常に無重力の状態にしている。

オブジェクト毎に別々のVisitorを適用するようにしていないのは、そうするためにはアプリケーション側でオブジェクトとVisitorとの対応を管理しないといけなくなり、Visitorパターンのメリットが大きく損なわれるからである。

次のエントリーで、StrategyパターンとVisitorパターンの例に対して、本体と切替可能処理のそれぞれのクラス階層にクラスを追加してみる。(続く)

続きを読む "StrategyパターンとVisitorパターンの使い分けに関する考察(3)" »

2011年04月25日

StrategyパターンとVisitorパターンの使い分けに関する考察(4)

これまで[1][2]にStrategyパターンとVisitorパターンそれぞれで作った引力モデルのシミュレーションに対して、以下のような要素を追加してみる。

  1. 物体の種類として、Square
    Squareの特徴:
    • 縦か横にしか動かない(縦方向か横方向かどちらか速度の大きい方に動く)
    • 但し速度は2次元(一方が空回り)で、全方向の引力の作用を受ける
    • 標準の引力は通常の距離の2乗に反比例する引力
    • 標準色は緑
  2. 引力計算の種類に、引力の方向が相手の方向より少しずれるCurlGravityを追加する
  3. 色設定の種類に、Blinkを追加する
それぞれ、PhysicalObject, GravityStrategy/Visitor, ColorStrategy/Visitorのクラス階層へ何かを追加するという例である。

Strategyパターンによるものに対する変更は、次のようになる。
class diagram
元のクラス図に対して、黄色で示されたBlink, Square, CurlGravityの3つのクラスを追加している。

これに基づいて変更したソースコードとJavaアプレットを、次のリンク先のページに置く。
・StrategySample3のアプレットとソースコードのページ
ソースコードの差分は、詳しいdiffの出力を末尾に載せているが、 Square.java, CurlGravity.java, Blink.java の3ファイルが新規に作られた他は、変更されたファイルは SampleApp.java の1つのみであり、その変更も、新たに追加したSquare, CurlGravity, Blinkの3つが選択できるようにGUIのボタンを追加したりボタンの動作を変更したりするものだけであり、それらを使わないアプリケーションには必要の無い変更である。
つまり、本体側のサブクラスの追加もStrategyの追加も、既存のクラスに全く手を入れることなく行うことができる(†追記部分に補足あり)ということであり、いずれの場合も、オブジェクト指向設計の基本であるであるOpen-Closed Principleを満たしていることが明らかである。

一方、Visitorパターンによるものに対する変更はかなり多い。
class diagram
元のクラス図に対して、黄色で示されたBlink, Square, CurlGravityの3つのクラスを追加した他に、Visitorの階層のGravityVisitor, DefaultColorizerを除く全ての既存のクラスに変更が入っている。

これは、Visitorインターフェースにvisit(Square)を追加した為、Visitorインターフェースを実装する全てのクラスにvisit(Square)を追加する必要があるからである。もちろんVisitor階層で実装を継承できる場合は追加不要だが、Visitorパターンがその効果を発揮する用途ではVisitor同士は役割が類似しないことが多い(後述)というよりむしろ全く異なることが多い為、Visitorインターフェースが変更されても変更せずに済むのは、親クラスを僅かに拡張をするようなクラスに限られる。
また、Visitorインターフェースにvisit(Square)を追加しなくても良いのは、SquareがVisitorを一切acceptしない(accept()が何もしないか例外を投げる)場合のみである。(accept()でのvisit(this)はコンパイルエラーになる)

これに基づいて変更したソースコードとJavaアプレットを、次のリンク先のページに置く。
・VisitorSample3のアプレットとソースコードのページ
ソースコードの差分は、同様にdiffの出力を末尾に載せているが、 Square.java, CurlGravity.java, Blink.java の3ファイルが新規に作られた他に、 SampleApp.java, ColorVisitor.java, DefaultGravityApplier.java, Gradation.java, NegativeColorizer.java, NormalGravityApplier.java, RepulsionApplier.java, Visitor.java の8つのファイルが変更されている。
SampleApp.javaの変更は、Strategyパターンの場合と同様、使用者側が新たなクラスを使う為の変更であるが、その他は既に実装されているメソッドをcopy&pasteしたような怠惰な追加である。末尾のdiffの出力は先頭が+の行が追加された行であり、変更箇所の前後3行が参考の為に表示されているが、SampleApp.javaを除く前述の7ファイルの追加内容は、それらのすぐ上に同一または類似の処理があることが見て取れると思う。いかにも冗長である。

ただ、これら7ファイルは全て、PhysicalObjectの階層にSquareクラスが追加されたことに対応してvisit(Square)が追加されたものであり、CurlGravityやBlinkの追加に伴って発生した変更ではない。よって、VisitorパターンはVisitorの追加に対しては変更箇所が閉じている(Open-Closed Principleを満たしている)ことがわかる。
繰り返しになるが、visit(Square)を追加しなくて良いのはSquareがVisitorをacceptしない場合のみであり、それはVisitorパターンの適用外ともいうべきもので、そういう場合には変更に閉じていると言えるものではない。

以上より、StrategyパターンとVisitorバターンの違いとしては、次のようなことが見られる。

  • Visitorパターンの場合、本体側のクラス階層にサブクラスが追加されると、Visitor階層全体に変更が及ぶ。
    Visitorパターンの宿命のようである。
  • Visitorパターンでは、いずれのVisitorクラスも、本体側の全ての具象クラスについて別々のメソッドを持つ。
    具象クラス毎に処理が異なることが少ない場合は、適しているとは言い難い。一方、Strategyパターンでは、具象クラス毎に処理が異なるStrategyのみ、具象クラス毎にStrategyのクラスを別にすることが可能である。
  • Visitorパターンでは、本体側のクラスが主体となってその処理を実行することができない。
    accept()が呼ばれるまではVisitorが実装する処理を実行できない。その為、例えばメソッドの途中でVisitor側にある処理を呼ぶことは困難である。(抽象Visitorクラスがイベント発行要求を受け付けて、Visitorインスタンスを管理するクラスに通知して、acceptを呼ぶような、トリプルディスパッチが必要かも知れない)
  • Strategyパターンが本体側のクラスのインスタンス毎にStrategyを持つのに対して、Visitorパターンは特定のインスタンスとの関連が無い。
    切替可能な処理を繰り返し実行するのであれば、Visitorパターンの場合はVisitorのインスタンスを別に管理する必要が生じる。
    切替可能な処理を1回だけ、複数のオブジェクトに対して実行するのであれば、Strategyパターンの方が処理が煩雑になる。全オブジェクトに(抽象化された)同じ処理を1回だけ適用したい場合には、Visitorパターンが有利である。
  • Strategyパターンの場合は、Strategyの使われ方が決まっているので、追加できるStrategyの自由度は限定的だが、Visitorパターンの場合は任意と言うに近い自由度で処理が追加できる。

そもそも、Visitorパターンが有効な場合は相当限られると思う。
適用されるクラス群は抽象化されているのだからそれなりに共通の特徴を持つだろう が、
・Visitorから見るとクラス毎に処理が違うくらいにはサブクラスは異なる特徴を持ち、
・Visitorが行う抽象的な処理の種類はStrategyとして共通の特徴を持たないくらいには異なる、
ような場合ということになる。筆者がこれまでに見たことがある例は

  • オブジェクトダンプのようなデバッグ表示(toString+printのようなもの)
  • ファイル保存などのための、オブジェクトのフォーマッティング
くらいであるが、他にはなかなか思い付かない。ファイルハンドルのように、ストレージはファイルシステムかHDDかデータベースかネットワーク越しの何かかわからないようなものに対する処理を追加できるようにしておくような場合だろうか。

続きを読む "StrategyパターンとVisitorパターンの使い分けに関する考察(4)" »

2011年04月29日

アジャイルセミナー傍聴録

いつも返却ポストとして利用している図書館で、参加費無料のアジャイルソフトウェア開発のセミナーをやるというので、今借りてる本の返却期限はまだであるが、自転車を30分漕いで行ってきた。

【内容】

  1. Kent Beck氏からのビデオレター上映
    被災した日本の皆様にお悔やみ申し上げますって感じの20秒くらいのもの。
    再生後、日本語訳が説明され、それを踏まえてということで、もう一度再生された。
  2. テクノロジックアートの長瀬氏による講話
    後述
  3. ThoughtWorks社のDavid Joyceという人のオーストラリアからのテレ講演
    System thinkingとかLean開発とか
  4. パネル討論会
    後述

【長瀬氏のお話】
これまでは、アジャイル開発をやってきた人はオブジェクト指向のプロフェッショナルだったりして、アジャイル開発でうまく行ったという話も、アジャイル開発でなくてもうまくできるような人がやってた。それに対して、最近はウォーターフォールをやってた所がやり始めている。

アジャイル開発を始めるには、まずそこのカルチャーを見極めないといけない。きちんとドキュメントを作ってきた所なのか、インターネット系でオープンソースをばりばり使ってるのか、新しい技術が好きで次々に取り込んでるのか、若い人中心でゲーム感覚で作っているのか。

日本ではアジャイル特有の言葉はあまり使わない方がいい。既存の概念に囚われない目的でそうするものだが、既存の概念を捨て去るのは合わない。
全員がプログラムも設計もできる、というようにするのは難しい。それらは分業することになるが、そうするとオペレーション(イテレーションの周期)が2週間では厳しい。4週間とかになるだろう。

アジャイルにはオブジェクト指向設計が大事。最適な設計はオブジェクト指向設計から。やったことがない所ならオブジェクト指向の教育をみっちりと。

アジャイル導入には、まず手順書を作ること。テストを作ってから中身を作って、とか、それぞれの人の役割をはっきりするとか。それにはじっくり1ヶ月はかかる。

テスト駆動開発はユーザーの要求を漏れなく反映できるかにかかっている。欧米ではそのためのしっかりしたツールがあるが、欧米ではユーザー(顧客)が技術に明るいことが多く、ツールの作りもそれが前提になっている。それに対し、日本のユーザーは漠然とした要求しか出さないケースが多いので注意が必要。
ツールを使ったら使ったで、その内毎日のCI(Continuous Integration)つまり結合と自動テストが夜中に終わらないということも起こることがある。考えるべきことは多い。
拠点が分散しているとツールを使わざるを得ない。しかし、日本ではこれまでアジャイルは1つの拠点で小規模にされることが多かったので、アジャイル特有のツールが広まっていない。

【パネル討論会】
テーマ:アジャイルは失敗するって本当ですか?
パネラー:長瀬さん(T)、細谷さん(H)、永田さん(N)
司会:前川さん(M)

M: 本当です。
アジャイルは今第2次ブーム。
アジャイル宣言から10年、最初は技術者が主体だったが、ちょっと下火になった時期があって、今は経営陣が興味を持つようになってまたブームになってきた。
それ故、十分な知識が持たれないことが増えてきた。

(以下、Qは会場からの質問、Aは会場からの回答、Cは会場からのコメント)
M:パネラーの皆さんにとって、Agileとは、一言で言うと?
H:開発をマネジメントする為の有効なフレームワークの1つ。
N:"interplay"
(JAZZの用語、誰かがピアノを弾いてる所に、阿吽の呼吸で合わせていくようなこと。
営業でも開発でも、メンバーの誰かが課題やアイデアを持ったら、他のメンバーがそれに合わせて動く、のような意味合い。)
T:日本のソフトウェア開発を崩壊させるかも知れないもの。
それについていけないと、日本のソフトウェア開発が無くなってしまうもの。
M: 皆さんにとって、何をもってAgileが成功したと言えるか?
H: お客様が満足するか、プロジェクトが計画通りに進むこと。
N: Deliveryを満たすこと。
T: 日本では、イテレーションが回るようになったこと、開発が楽しそうであることを言うのではないか。
お客様が要求をはっきり言わず、具体的な要求は変化するので、機能追加型で開発できないといけない。その為には、リファクタリングもできないといけない。そこまでできて、イテレーションが完結すると言える。
Q: アジャイルを始める動機は何が多いか?Waterfallに失敗したから?
T: Waterfallが失敗したから、と言って相談に来る人はいない。このままではダメになるのではないか、Waterfallだけではだめなのではないか、という感じの漠然とした危機感を持っている人が多い。
Q: 欧米では、組み込み系と業務用システムで、どちらの方がAgileが成功しているか?
(中略)
H: ドメインによって違いはあると思う。
ハードウェアまで作り込むとか難しい物理的な制御をするなら、最初にある程度きちんと作らないと、全然動かない。
業務用システムを作るなら、最初は簡単に作って見てもらうことも可能。
T: 欧米では、開発が相当早い。
CIが活用されていて、毎回3,000のビルドが行われたりしている。
ツールチェーンが確立していて、ストーリーカードから実装、CIまでが繋がっている。
ビジネスアナリストからエンジニアまで、速く作れる体制が整っている。
ビジネス分析者がエンジニアと同じ稼ぎ。
ソフトウェア工学的には、日本はかなり遅れていると思わざるを得ない。
Q: 管理するツールという面で、Redmineはどうなのか?
A(阪井さん): 何の為に使うかによる。ツールはプロセス改善のために導入されるべきもの、何の為にツールを使うかを明確にすることが大事。
H: Redmineでは、メンバーにある程度マネージメントの権限を委譲できるのが良い。
ガントチャートを更新するというのは結構大変な作業。
但し、より上位のスケジュールとの差異をどう管理するかが問題。
M: Redmineの失敗事例として、ただチケットを発行して現場任せにして、遅れがあれば催促する、ということをやって、現場の担当者がチケット恐怖症になり、自分からはチケットを発行しないようになったということがある。
T: ツールを使うのが目的になるのではなく、マニュアル(手作業)でやってみて問題があったらツールを使う、というのが正しい。
欧米ではツールとマニュアルと両方やっている。ツール使いながらストーリーカードが壁に貼ってある。
M: PDCAを回す(計画を直しながら進める)のとタイムボックスを守るのとの違いは?
N: Agileはプロセスなのか、プロセス改善なのかという話があった。
Engineeringから見ると、Agileはなかなか大変だと思う。
H: 不安感が生産性に影響すると思っている。漏れ聞こえる噂に左右される。
タイムボックス化の効果は、2週間は邪魔が入らず集中できること。
M: 結局、マネージャーが、このメンバーで何が作れるか、どう成長するかをはっきりと予想できるかどうかにかかっているような気がする。
H: そこまでわかってたらWaterfallでできるのではないか?
C: 2002年くらいの論文では、Waterfallは見直されていて、2回回せばいいという論文も出ている。
?: Waterfallの知識が無いとAgileはできないと思う。Waterfallは、プロジェクト検証の過程が無いのが問題なだけではないか。
H: WaterfallでもAgileでも、実行可能だと大多数の人が思っている計画しかうまくいかないというのが真実ではないかと思っている。スキルが上がると、Waterfall力がついてくる。
Q: Agileって儲かるのか?
T: 儲からないと思う。
ユーザーから見て、Waterfallは途中が見えないから博打、Agileは見えるから安心ではある。開発とユーザーとの信頼関係は上がる。しかし、Agileは失敗したらユーザーの責任になることがあまり理解されていない。
M: これからAgileを始めたい人に一言
H: 失敗する所はちゃんとわかってやらないから失敗する、という話もあるが、興味あるならやってみれば良いと思う。
N: 海外の人は、AgileはEngineeringだという意識が強い。だから進んでいる。
Lean開発の目的がqualityになってるのがやっぱり凄いと思った。
T: 大手は大体そのどこかではやっていて、失敗した経験も持っているので、今後は失敗は減っていくだろう。
最初から失敗したくなかったら、コンサルタントを雇うとか、金が無かったら、こういうセミナーで擬似的にやってみるとか。
(その他の会場から出た質問で答えが出なかったもの)
Q: 外注さんが含まれる場合、どうお願いすればいいのか?
Q: 詳細設計ってどうやるのか?

続きを読む "アジャイルセミナー傍聴録" »

About 2011年04月

2011年04月にブログ「Weblog on mebius.tokaichiba.jp」に投稿されたすべてのエントリーです。過去のものから新しいものへ順番に並んでいます。

前のアーカイブは2011年03月です。

次のアーカイブは2011年05月です。

他にも多くのエントリーがあります。メインページアーカイブページも見てください。

Powered by
Movable Type 3.35