2010年7月29日木曜日

TestFirstで新人教育もやれば?という話

最近、あるソフトハウスの新人が、準委任契約の開発現場にアサインされるにあたって、顧客企業の開発部門の責任者の面接を受ける事になり、その現場に居合わせる機会を得た。

で、本人のスキル不足に関しては、新人だからと言う事で、まあしょうがないという雰囲気だったが、xUnit の経験が無いという話になると、顧客側責任者から、その新人に同行したソフトハウスの上司に対して厳しい指摘が飛んだ。

曰く、「これからの現場では、xUnit を用いたテストコードによる自動テストを"しなくてよい"なんて事はあるわけが無いから、新人研修では絶対にテスト駆動開発も教えるべき。」という事だった。

私としては、立場上、浮かれた態度を取れない状況だったので、その場ではほぼノーリアクションで神妙にしてたけど、内心は「我が意を得たり」の心境で、ちょっと気分が良かった。

開発の現場にいると、「先にやっておくべきことを後に回すと、利子がついて何十倍にもなって跳ね返ってくる」という事が実によくあるが、この最高の典型例がユニットテストだと思う。

テスト・ファーストとテスタビリティの関係は、「テストを先に書くから、低テスタビリティ・コードが書きにくい」という面と、「低テスタビリティ・コードが書かれる前だから、テストも先に書きやすい」という面が、互いにループ状に補完しあうようになっている。

このシンプルで美しい因果関係がわからない人が、未だに多い。先に書けない人間が後で書けるわけが無いのに、後の方が書きやすそうなんて勘違いして、結局挫折して、テスタビリティもカバレッジも最低のコードを垂れ流してくる。

という訳で、「後付テストの方がテストファーストより簡単」なんて考えてる迂闊なPGをこれ以上増やさないためにも、新人の研修プログラムもテストファーストで組み立ててみてはどうかと思う。

前述の面接での助言だと、単に新人研修にテストファーストを組み入れましょうという話だが、それだけだと手ぬるい。そんな事だと、テストコーディングはカリキュラムの最後の方にまわされて、終いには「後は各自勉強する事」なんて感じで省略されるのがオチ。

だから、まず最初にテスト。プロの現場の教育は「テストありき」で教える。高カバレッジ・高テスタビリティを最初から維持したまま、プログラムが成長していく様を骨の髄まで体得させる。

つうか、まあ、指導者のスキルも物凄く問われてしまうが。

2010年7月26日月曜日

Test Smells - Slow Tests

TestComplete というテストツールを使って UI操作を自動実行するスクリプトの記述作業に、途中参加することになった。

話を聞くと、既に完成した部分では、テスト実行時間がハチャメチャに長いスクリプトになっているらしい。一つのフォームについて、合計して小一時間のテスト群があって、それが数十フォームあるから全ケースで軽く一日は超える事になる。これは、かなりのレベルの Slow Testsだと思う。

つうか、Slow Tests も困った事だが、それ以上に脱力するのが、その弊害を誰もまじめに考えて来なかったと言う点だったりする。

しかも、今までこの自動化テストを指揮してきたリーダが、同時に Coutinuous Integration に関連するチームのメンバでもあったりして、そんな人が Slow Tests という Test Smell の中でも最たるものを等閑視してきたわけだから、何かビックリしてしまう。

今まで、常時結合とかについて議論してきたのはなんだったんだろうと、こっちがしょんぼりしてしまう。Daily も無理じゃん・・・

とりあえず気を取り直して、以下、教科書どおりの処方
  • 第一候補:Fake Object パターンを使って、遅い部分を置き換える。
  • 第二候補:Shared Fixture パターンを使ってセットアップコストを抑える(但し、Erratic Test アンチパターンを避けるため、immutable(不変)にすること)。
教科書の方はどちらかと言うと TDD系のホワイトボックステストである一方、今度やることになるのは後付のブラックボックステストなわけで、若干状況は違うけど、原因はやはり教科書どおりの「Slow Component Usage」と「General Fixture」という事になる。毎回のログインだとか起動処理に時間が掛かっているので、つまり「General Fixture」のセットアップに「Slow Component Usage」が含まれていると言う事になるだろうか。

しかし、こういう風に後から入って行って何かを是正しようとすると、たいてい前任者の心理的抵抗に会ったりしてちょっと面倒くさい(本当はシステム開発を面白がるブログのはずなんだが、最近は愚痴の方が・・・)

2010年7月19日月曜日

Software factory → 技術者の棲み分け

自動車工場の生産ラインを超おおざっぱに言うと、だいたいジャングルジムくらいの機械をベルトコンベアで何台かつなげたもので、いろんな小っさい部品(輪っかとか、丸っこいのとか、筒みたいなのとか)を組み合わせて、より上位の足回りやブレーキといった部品を作るような、一連の流れ作業を担っている。

ラインに組み込まれる個々の機械は、部品と部品を組付けたり、溶接したり、塗装したり、油を注入したりするもので、あるものは全自動、別のものは半自動だけど、人手が介入する部分は単純化されていて、工学的素養や、職人的技能が要求される事はほとんどない。出稼ぎ労働者や期間工が、担当したりする。

工場では、新車種対応だとか、増産だとかいったきっかけで、生産ラインを組み替えたりするので、そこに組み込む機械を、自社の部門だとか外部の「ナントカ精機」みたいな機械製造会社にオーダーメイドで発注する。で、普通は、設計、電気、組み付けのそれぞれの職人がアサインされて、協力して機械を製作する(旋盤やフライスを使って、鉄の塊から部品を切り出す加工屋さんも関わってくる)。

この職人さん達は、それぞれの担当分野のプロフェッショナルなわけだけど、それぞれの腕前が品質や生産性に反映するから、やり甲斐があって面白いし、だからよく勉強もする。それに基本的に世の中に一台から数台しかない機械なので、なんとなく愛着のようなものも持っていたりもする。

当たり前の事だけど、生産設備を作る機械職人と、その設備を使って部品を組み立てるライン作業者との間には、基本的には棲み分けがある。メーカの社員が両方をこなす事も、あるにはあるだろうが、基本的には前述のとおり、機械職人は機械屋さんだし、ライン作業者は出稼ぎの期間工だったりする。仕事の成果物も違うが、それ以前に、持っている職能も、もの造りへのスタンスも背景も、全く異なっている。

前置きが長くなったが、このところ聞かなくなったソフトウェア・ファクトリについて、上述のような、「技術者の棲み分け」を促進するのではないかと、ちょっと期待していた。つまり、ファクトリという生産設備を作る高スキル・グループと、それを使って製品を作る低スキル・グループに、いっその事、従来以上にスッパリ分離してしまってはどうかという疑問に、答えを提供してくれるのではと。

従来、SI屋が技術者の棲み分けを施す場合、フレームワーク/ライブラリに関連するチームに比較的高スキルの要員を割り当てて、それを用いるビジネスロジックを担当するチームに低スキルの要員を割り当てる事が多かった。

でも、この役割分担だと、つまるところ同じ平面上で共通部分と固有部分に要員を振り分けているにすぎず、結局は同じ言語、同じ規約、同じ最終成果物に対しての作業になるわけだから、いたるところでギャップが生じて、互いの不経済を引き起こす。

すなわち、低スキル技術者は、高スキル技術者達の間ではごく当たり前な慣用句に過ぎない、ありふれたデザイン・パターンやイディオムがチンプンカンプンだったりするし、一方、高スキル技術者の方でも、三項演算子すら分からない低スキル技術者が迷子にならないように、自己の能力も言語/APIのポテンシャルも大幅に抑制する事になる。

例えば、良かれと思って、「流れるようなインターフェイス(fluent interface)」のスタイルでAPIを書いたとしても、使う側が最底辺技術者のグループだと、「いつもと違う。見たことが無い。」なんて感じで、総スカンを食らう可能性がある。

こういった無駄な軋轢を避けるためにも、高スキル技術者をメタレベルの作業領域、つまり生産設備=ファクトリの開発作業に従事させて、低スキル技術者とは干渉しようもないレベルに分けてしまうのが良案なのではないかと。(もちろんギャラも、容赦なく差をつけるべきだが。)

低スキルな技術者達というのは、プログラム言語や APIについて勉強する事が、本当に何よりも嫌いでたまらない人達なわけだから、そんな理不尽な苦痛は、人道的観点からもなんとかして少なくしてあげたい。そのために、覚える事がいっぱいな従来通りの汎用言語に替わる簡易な言語として、DSL を与えてあげるのが良いのではないか。

この DSL を定義する 高スキル技術者グループの方でも、リテラシの貧弱な読者を気にする事無く、スキルを最大限に発揮して、言語/API の本来の力を最大限に引き出して、最高のコードを書くことができる。最も簡易で優しいドメイン特化言語を、最も高度な技術で、のびのびと開発すればいい。

と、まあ、理想はこうだけど、何をどう分離して、どこまでファクトリ化するか具体的に考えたら、やはりなかなか難しい。正にそれをソフトウェアファクトリが提示していたんだろうけど、普及する前に消えてしまったようだし、やはり何か無理があったのか。

2010年7月11日日曜日

use case patterns の備忘録

Patterns for Effective Use Cases』から、パターンの要約をメモっておく。

■■■ Team のパターン
★ SmallWritingTeam
各成果物をレビューして仕上げる担当者数は2,3人に抑える事。大人数を動員するときは TwoTierReview パターンを使う事。

★ ParticipatingAudience
顧客や内部のステークホルダに、なるべく積極的にユースケース作成プロセスに参加してもらう事。

★ BalancedTeam
異なる専門分野の人をチーム構成に含めて、ステークホルダの利益を開発プロセスの中で擁護していく事。特に設計者とエンドユーザは確実にチームに含める事。

■■■ Process のパターン
★ BreadthBeforeDepth
まず最初に概観レベルのユースケースを作っておいてから、関連するユースケース群を横断しつつ、詳細レベルの記述を段々と追加するような作業の流れに従う事で、労力の無駄な消耗を防ぐ事。

★ SpiralDevelopment
イテレーションを繰り返す中で、ユースケースの精度と正確性がだんだんと増加していくように、反復的かつ「広さ優先」の作法でユースケースを開発していく事。

★ MultipleForms
プロジェクトに関連するリスクと、関係者の好みを汲み取りつつ、ユースケースの書式を選択する事。

★ TwoTierReview
2つのタイプのレビューを催す事:第一にチームの内輪だけで数回行う小さなレビュー。第二に完全なグループで、一回だけ行うレビュー。

★ QuittingTime
ユースケースが出来上がってステークホルダや開発者など聴衆のニーズを満たした時点で、そのユースケース開発はとっとと止めてしまう事。

★ WritersLicense
書き方の小さな違いに無駄にこだわらない事。一たび QuittingTime の条件を通ったユースケースについては、ライタが小さな様式の違いに関する"ライセンス"を得る事ができるようにする事。

■■■ Use Case Set のパターン
★ SharedClearVision
システムの目的を明確化し、組織のミッションを支援するような声明を準備して、プロジェクトに関係する全員が読めるように公開する事。

★ VisibleBoundary
システムと対話する人間と設備の両方を列挙して、システムとその環境との境界を可視化する事。

★ ClearCastOfCharacters
システムと対話するものであるアクタと、システムに対して果たすべきものであるロールを識別し、それぞれについて明確に説明する事。

★ UserValuedTransactions
アクターのビジネス上の目的を満たすためにシステムが提供する、価値のあるサービスを識別する事。

★ EverUnfoldingStory
展開して詳細を見たり、畳み込んで全体的な文脈を重点的に示したりできるような、階層的なストーリとしてユースケース・セットを組み立てる事。

■■■ Use Case のパターン
★ CompleteSingleGoal
よく定義された完全な一個のゴールを示すように、各ユースケースを書く事。(そのゴールは、EveryUnfoldingStory における任意のレベルでもある。)

★ VerbPhraseName
プライマリ・アクターのゴールを表現するような、能動態の動詞句でユースケースを名づける事。

★ ScenarioPlusFragments
失敗を考慮しない単純なシナリオでサクセス・ストーリーラインを書き、その下に代替事象の発生を示すストーリの断片を記述する事。

★ ExhaustiveAlternatives
処理すべき全ての代替および失敗を、ユースケースにおいて漏れなく捕捉しておく事。

★ Adornments
ユースケース・テンプレートのシナリオ・テキストの外に、ユースケースの関連付けに役立つ補足情報を保持するための追加フィールドを作成する事

★ PreciseAndReadable
ステークホルダが読んで評価する気になるレベルの読み易さで、尚且つ、自分達が何を構築しているのか開発者が理解できるレベルの正確さで、ユースケースを書く事。

■■■ Scenarios and Steps のパターン
★ DetectableConditions
検出可能な条件のみを含める事。システムに与える正味の効果が同じである条件はマージする事。

★ LeveledSteps
シナリオの長さは、3ステップから9ステップにする事。

★ ActorIntentAccomplished
各ステップを記述する際、どのアクターがアクションを実行し、それにより何をアクターが得る事になるのか明確に示す事。

★ ForwardProgress
アクターを前に進めないステップは排除するかマージする事。読者がシナリオの進行に付いて来れなくなる様なややこしい経路は簡略化する事。

★ TechnologyNeutral
各ステップを書く際、IT技術に中立となるよう留意する事。

■■■ Use Case 間の関連のパターン
★ CommonSubBehavior
「包含」される下位レベルのユースケースを用いて、共有されるアクションのコースを表現する事。

★ InterruptsAsExtensions
シナリオの多くのステップに代替コースが割り込んで来る場合、拡張ユースケースを作る事。

★ PromotedAlternative
ユースケースに過度に影響する複雑な代替は、分離したユースケースへの移動を考慮する事。

★ CapturedAbstraction
汎化した抽象ユースケースの作成を考慮する事。その抽象ユースケースを特化する具象的・個別的なシナリオは、それ自身の具象ユースケースに置く事。

■■■ 既存 Use Cases の編集のパターン
★ RedistributeTheWealth
長くて扱いにくい経路や、複雑すぎる拡張は、それ自身のユースケースを別途作って移動する事。

★ MergeDroplets
関連する小さなユースケースやユースケースの断片は、同じゴールに関連するものをマージして、別途ユースケースを作成する事。

★ CleanHouse
システムに価値をもたらさなかったり、既にアクティブ・リストにないユースケースは取り除いてしまう事。

三項演算子を使うべき理由

三項演算子を使うべきでないとする規約や現場って、結構多い。

それに対する「使う」派の主張もたまに見かけるが、
  • 「控えめに使うなら許されるべき」なんて消極派だったり、
  • 「三項演算子すら理解できない奴はクズ」なんて議論拒絶派だったり、或いは
  • 「三項演算子の方が格好良くて好き」的な頭脳労働苦手派であったり
する。

自分は使用肯定派だけど、なるべく合理的に三項演算子について考えてみたい。日曜なのに暇だしな。

最初にまず、「if 文ではなく三項演算子を使うべき」状況を考えて、その後で、良くある三項演算子否定論への異議を述べてみる。(言語は C# とか Javaを想定)

■■ if 文を避けて三項演算子を使うべき理由

★ 変数の宣言と定義を同時にできる
一時変数への値の設定について、宣言と同時なのと宣言から離れているのとで、どちらが良いコードかという問題だが、後者の「離れて」が正解なんて言う人は聞いたことが無いので、説明は割愛。(一応手持ちの資料を調べると、『Code Complete 上巻』の変数の部に詳述されているので、理屈を確認したければこの辺りを読めばいい)
public int Foo(bool f)// if 文版
{
  int i;
  if (f)
  {
    i = 100;//← 宣言した行から離れている
  }
  else
  {
    i = 200;//← 宣言した行から離れている
  }
  // i を 使う
}

public int Foo(bool f)// 三項演算子版
{
  int i = f ? 100: 200;//← 宣言した行で値を設定している
  // i を 使う
}
Javaならば更に final を付けて、より低リスクな安心コードにできる。(残念ながら、C# の const では、同様の安全策ができそうでできない。)
public int foo(boolean f) {
  final int i = f ? 100: 200;← 誤変更のリスクが解消
  //ここで i を変更しようとするとコンパイルエラー
  // i を 使う
}
また、上のサンプルコードでも明らかなように、「一時変数の宣言箇所は、使用する箇所のギリギリにまで近づけるべき」と言うプラクティスについても、三項演算子の方がより準拠している。

★ 一時変数が少なくて済む
三項演算子はもちろん演算子だから、式を書ける所ならば普通に使えるので、わざわざ作業用の一時変数を使わないで済む場合がある。
※一時変数の使用と不使用とでどちらが望ましいかなんて解説は省略。
※『リファクタリング』に「説明用変数の導入」という一時変数を増やす事になる小技が載っているが、それとは別の話
public void Foo(bool f)// if 文版
{
  string arg;
  if (f)
  {
    arg = "one"; 
  }
  else
  {
    arg = "two"; 
  }
  Bar(arg);//作業用の一時変数にわざわざ入れる羽目になる。
}
public void Foo(bool f)// 三項演算子版
{
    Bar(f ? "a" : "b");//式なので普通に使える。一時変数不要。
}

★ 重複コードを解消できる
上の どちらのFoo()も、条件分岐/条件演算を 別のメソッド Baz() に移して値をすぐに return させるようにすると、共にBar(Baz(f))という形に置き換えることができるが、それでも、まだ微妙な重複が残る。
public void Foo(bool f)
{
    Bar(Baz(f));
}
public string Baz(bool f)// if 文版
{
  if (f)
  {
    return "a";
  }
  else
  {
    return "b";
  }
}
public string Baz(bool f)// 三項演算子版
{
  return f ? "a" : "b";
}
実務上は、このreturn の重複についてまでも、Code Smell と捉えて、厳しく除去するなんて事はあまり無いが、例えば Baz()から値を返す前に何かの書式化を施すような変更を想定すると、これだって立派な重複コードだと言う事が分かる。目くじらを立てる事もないほどではないが、無ければ無いに越した事は無い。

★ 不要なブロックを減らせる
ブロックが多い(深い)のと少ない(浅い)のでは、少ない方に決まっているという普通の話。(自明のように見えるが、実はプログラマの中にはブロックをどんどん深くして悦に入る人もたまにいる。これ以上くどい説明もアレなので省略するが・・・)
コードブロックに関して突き詰めていくと、ブロックそのものが、長過ぎるメソッド/一時変数の濫用/重複コード/スパゲティコード/オブジェクト指向を無視した手続き型ロジックやらの温床でもあり元凶でもあるように見えてくる。他のトレードオフも考慮した上で、できるだけ式かメソッド呼び出しに変えてしまった方が、将来的にも安全なコードになる。

三項演算子を「使うべき」理由は、こんなところか・・・
続いて、よくある三項演算子反対の意見に反論してみる。

== == == == == ==
■ 三項演算子否定論への異議

★三項演算子は難しいから禁止すべき
そもそも「難しいか否か」なんて主観的判断が、合理的評価基準として妥当なのか疑問だが、差し当たりこれを認めるとして、それならば他の言語要素に関しても三項演算子より難しいものは否定してしまうのかという話になる。LINQ はどうか?ラムダ式はどうか?ジェネリクスは簡単か?

何かの言語要素を難しいと感じた誰かさんが(難しさを認識する事自体は望ましい事だが)、それを一律に禁じてしまうような事で、言語という道具と、それを操るプロフェッショナルから、投下したコストに対する効用を最大限に引き出す事が本当に可能なのか疑わしい。ちゃんと分かって、禁止しているのだろうか?むしろ、その禁則さえなければ得られたはずの利益を捨ててしまっていないか?

また「平均的プログラマの技術水準」なんて怪しい設定を持ち出して、三項演算子は無理なんて主張する人も多いが、どこに根拠あるんだろう?というか、
(isNegative ? -1 : 1) * absoluteValue
の意味が分からない人が、更に高度な他の文法要素を使いこなしたり、あるいはテスト駆動開発でモックテストを書いたりできる訳がない。

「三項演算子ができないレベルで妥協した方が、人材調達が容易」なんて言い分もあるようだが、それって「我々のスタイルは、基礎的な文法要素も使えない、最底辺PGによる人海戦術です」なんて言うのと同義なわけだけど、マジでそんなので良いのかな。三項演算子どころではない大問題だと思うんだが・・・

★ 三項演算子は読みにくいから禁止
三項演算子の方が読みやすいと言う人もいるし、どっちでも変わらないという人もいて、結局、単なる主観なわけで、フォーマルな規約の根拠としては元々ふさわしくない。

あと、読みにくさの話になると、ことさら読みにくくした三項演算子コードのサンプルだけを引き合いに出して「ほら、こんなに読みづらい」なんて言う人が必ず出て来るけど、そういうのはスルー。

★ 三項演算子はミスを生じやすいから禁止
自然な対策としては、作業ミスを誘発しやすい箇所を識別した上で、括弧付けの規約などで可読性を確保すればいいのであって、三項演算子そのものの禁止にはならないはず。これについても、数ある言語要素の中でなぜ三項演算子だけが槍玉に挙げられるのか分からんが。
Sun のJava規約みたいに 2項演算子を含む条件部を括弧でくくるなど

★ 三項演算子が嫌いだから禁止
三項演算子を使う理由を「好きだから」という情緒によってしか説明できない人と同じくらい、知的作業に向いていない。よって、この手の輩はコーディング規約策定には関与すべきでない。


なーんて、なぜか書いているうちにエキサイトしてきて、文章にトゲが入ってくる・・・
やはり三項演算子談義には、何か人の攻撃性を刺激するような魔物が住んでいるのか・・・

2010年7月6日火曜日

functional test と unit test の違い

functional test と unit test の違いについて、非常に良い言葉を見つけたので貼っておく。[Testing, fun? Really?]

Unit tests tell a developer that the code is doing things right; functional tests tell a developer that the code is doing the right things.

副詞と形容詞の違いで、正当性を表す”right”がどの語に掛かるかが違ってくる(日本語に訳すと何故か鮮やかさが無くなってしまう・・・)。

この functional test と unit test の違いについては、開発プロセスについて決定権を持っているようなポジション人ですらよく分かってなかったりして、いろんな現場を渡り歩いているとたまにガッカリする事がある。

よくある誤解は、「xUnit を使ったら、そのテストは unit test」、「xUnit を使うから unit test」ってやつで、目的と手段が逆転しているパターン(別に NUnit でfunctional test も普通にやるし)。

さらにその上、自動テスト全般と xUnit を混同してる人もいて、「UIの unit test には TestComplete を使うから、Windows Forms のコードには テストコードは書く必要はないです」なんてメチャクチャな主張を聞く事もある。「結合テストをやるから単体テストはやりません」ってのと同じなんだが・・・

「コードが正しく動いて正しい事を実行している」って事のテストは、二つ別々の観点から別々に為されなきゃならないのになあ。

2010年7月5日月曜日

Mole で Mock してみるテスト

以前のポストで、こんなプログラムの Program.Main() について、、、
using System.Windows.Forms;
public class Class1
{
    public string Name { get; set; }
    public Class1(string name)
    {
        this.Name = name;
    }
    public void ShowName()
    {
        MessageBox.Show(Name);
    }
}
class Program
{
    public static void Main(string[] args)
    {
        Class1 class1 = new Class1(args[0]);
        class1.ShowName();
    }
}
、、、以下の観点でホワイトボックス・テストする事を考えた
  1. Main()メソッド内で、引数の先頭要素が Class1 コンストラクタに渡されている事を検証する
  2. 生成した Class1インスタンスの ShowName()メソッドが呼ばれている事を検証する。
  3. 但し、実物の ShowName()は、ユーザインタラクションを含むので呼ばれてはいけない。
前は、Typemockというプロダクトを使ったが、Moleという Microsoft謹製の Mockツールを見つけたので、これでやってみる。
[TestClass]
public class ProgramTest
{
    [TestMethod]
    [HostType("Moles")]
    public void TestMethod1()
    {
        //data
        string expectedName = "abcde";
        // observers
        string actualName = null;
        bool hasShowNameCalled = false;
        //arrange
        MClass1.ConstructorString = (me, name) =>
        {
            actualName = name;
            new MClass1(me)
            {
                ShowName = () => hasShowNameCalled = true
            };
        };
        //act
        Program.Main(new String[] { expectedName });
        //assert
        Assert.AreEqual(expectedName, actualName);
        Assert.IsTrue(hasShowNameCalled);
    }
}

こんな感じですっきり書ける。アトリビュートを見ると分かるとおり、NUnitではなく MS のユニットテストフレームワークを使っている。テストコードだけ見るとTypeMockよりシンプルかもしれない。

ただ *.moles というファイルで、"Mole する"クラス、即ちモックオブジェクトによって本物オブジェクトの呼び出しを迂回させるクラスを、アセンブリと共に指定する事になる。(ここで指定されたアセンブリに対応して、Moleされたクラスを含むアセンブリが VisualStudioによって自動的に生成されて、プロジェクト参照に追加される事になる。)

あと、Typemock と比べて困るのは、Visual Studio の UnitTest 機構と連動させる形じゃないと、いろいろ手間がかかるらしい事。ってか、NUnitと連動させて動かそうとしたけど、全然上手く行っていない。TestDriven.NETとの連携も、果たしてできるのかできないのか何だか良く分からん。

今の現場は VS2008 の standard で、UnitTest が付いてないので、導入は難しそう。そういえば、導入しにくいのは 有料の Typemock もそうだった。

なーんか、.NETって面倒くさ・・・

2010年7月3日土曜日

Agile ネタのPM試験小論文

四月に受けていた情報処理技術者プロジェクトマネージャ試験の合格通知が届いた。初めた去年、我ながら理解できない酷い結果だったので、とりあえず一安心。

勉強は、午後Ⅰの過去問のみを徹底的にやった。午前Ⅰは常識問題だし、午前Ⅱは去年勉強済みなので無勉。午後Ⅱの小論文は前回は採点されなかったので若干不安だったが、これも去年かなり練習したので今年はぶっつけ本番とした。

その代わりに、前回少なくとも8割は取れたと思っていたのに4割にも満たなかった魔の午後Ⅰのみ重点的に復習した。4日間くらい朝から晩まで、割と必死に過去問を解いた。

こんな点数になった
得点合格ライン
午前Ⅰ得点 91.80点60%以上
午前Ⅱ得点 84.00点60%以上
午後Ⅰ得点 78点60%以上
午後Ⅱ評価ランク A-

今回の午後Ⅰが予想8割で78点で、前回試験が予想8割で38点だったという事は、やはり選択問題のマーキングをミスって半分しか採点されなかった可能性が濃厚。これはこれで恥ずかしいが・・・


午後Ⅱの小論文は、問1の「システム開発プロジェクトのリスク対応計画」を選択して、アジャイル開発プロジェクトをネタにして書いた。

設問では、対象プロジェクトに内在するリスクとその分析、またリスク対応計画とその実施状況が問われたが、これが結構アジャイルと相性が良かったりする。個人的にも日頃から、「今時ウォーターフォールなんてやる人達って、その時点でリスク意識に問題があるのでは?」なんて疑ってしまうタイプなので、割とアジャイル+リスクは書きやすい。

ただ、終了前7・8分になってから、少なくとも600字書くべき設問ウの解答を400字しか書いていない天然ボケに気づいて焦った(そうか、これで去年も・・・)。終了30秒前くらいで200字書き足して、滑り込みで助かった。作文としてはちょっと酷かったかもしれないが、「問いに対する応答」としては一応何とかなったらしい。

それにしてもPM試験に限らず、情報処理技術者試験というとウォーターフォールってイメージだけど、反復型の軽量プロセスでもOKらしい事が分かって良かった。品質/コスト/納期とリスクについての問題意識をしっかり確立した上で、その処方としてのアジャイル導入であり、かつプロジェクト管理の視点でその効果を合理的に語れるなら、マイナス評価にはならないと言う事だと思う。

むしろ現実の業界で、未だにアジャイルについてルーズでアバウトでアナーキーなイメージを持っている人が多くて、こっちの方がよほど問題だ・・・

2010年6月28日月曜日

主語 ← ユースケースの最初の一歩

最近入った開発部隊で、ユースケースらしきものが作られていたが、どうにも酷すぎる。

最初のページにスティックマンを書いたら、残りのページのシナリオに何を書こうがOKなんて思ってるんだろうか・・・

ユースケースを知らないライタが命ぜられるまま書いて、それと同じくらいユースケースを知らないレビュアーが検定して、「どう役に立つか知らないけど、とりあえず何となく意味が通じない事もない気がする。スティックマンと楕円が、何となくユースケースっぽさをかもし出しているし。」みたいなレベルなのが見え見え。

これではいけないので、チェックリストを作って、ライタがレビュー前にそれを使って、ユースケースとしての最低レベルに自力で持って行けるようにしたい。レビュアーも自分が本来意識を向けるべきところにのみ集中できるはず。

という訳で、いつものとおり「まずは必ず他人の成果を利用する事から始める」ポリシーに従って、手持ちの本とかWebでみた資料をいろいろ思い浮かべる。で、Cockburn のユースケース本 に何かあったのを思い出し、実物を開いて裏表紙に載っている「Pass/Fail Tests for Use Cases Fields」 というリストを確認。

以下のような内容。
◆ Use Case Title
1. Is it an active-verb goal phrase that names the goal of the primary actor?
2. Can the system deliver that goal?

◆ Scope and Level
3. Are the fields filled in?

◆ Scope
4. Does the usecase treat the system mentioned in Scope as a black box?
5. If the system in Scope is the system to be designed, do the designers have to design everything in it and nothing outside it?

◆ Level
6. Does the use case content match the stated goal level?
7. Is the goal really at the stated goal level?

◆ Primary Actor
8. Does he/she/it have behavior?
9. Does he/she/it have a goal against the SuD that is a service promise of the SuD?

◆ Preconditions
10. Are they mandatory, and can they be set in place by the SuD?
11. Is it true that they are never checked in the use case?

◆ Main Success Scenario
15. Does it have 3-9 steps?
16. Does it run from trigger to delivery of the success guarantee?
17. Does it permit the right variations in sequencing?

◆ Each Step in Any Scenario
18. Is it phrased as a goal that succeeds?
19. Does the process move distinctly forward after its successful completion?
20. Is it clear which actor is operating the goal--who is "kicking the ball"?
21. Is the intent of the actor clear?
22. Is the goal level of the step lower than the goal level of the overall use case? Is it, preferably, just a bit below the use case goal level?
23. Are you sure the step does not describe the user interface design of the system?
24. Is it clear what information is being passed in the step?
25. Does it "validate" as opposed to "check" a condition?

◆ Extension Condition
26. Can and must the system both detect and handle it?
27. Is it what the system actually needs?

◆ Overall Use Case Content
29. To the sponsors and users: "Is this what you want?"
30. To the sponsors and users: "Will you be able to tell, upon delivery, whether you got this?"
31. To the developers: "Can you implement this?"

ユースケースを書く上での重要なエッセンスだけ抽出した、非常に濃いチェックリストなんだけど、うーん・・・

これは、すでにある程度の経験を積んだ人か、少なくともこの本をじっくり読了した人になら有用だけど、未経験者にはほとんど意味が通じない予感(日本語に訳したとしても)。もうちょい機械的というか事務的に作業できるのを作る必要があるなあ。

まあ、それは後で何とかするとして、ユースケースに余り自信のない人は、とりあえず各ステップの主語をちゃんと書く事から始めるのがお勧め。ただし主語といっても、定義が若干あいまいな日本語文法のそれというより、英語のような動詞に対するものとしての主語。もう少し言うと、状態動詞ではなくて動作動詞で、さらに能動態の主語。

動作の主体、ボールをキックするその人、動きが生じて状況が前進する瞬間の主役を主語として、ステップを記述する。そうすると、ユースケースにまつわる他の事も分かってくる。つうかそれが駄目だと、ユースケース全体の他のすべての項目も多分駄目。

つうわけで、主語だけはしっかりと書くべし。まずはそこからだ。
・・・なんて、上から目線で言ってみる。

2010年6月27日日曜日

AntiPatterns over DesignPatterns

日ごろからデザインパターンよりアンチパターンの方にこそ着目すべきだと、常々考えている。

GoFのデザパタ本の最終章で、デザイン・パターンこそがリファクタリング(再分解)に方向性を与えるといった有名な記述があって、後にファウラーのリファクタ本が出た時に、みんな読み返して「やっぱデザパタだね」なんて頷いたりしたが、それでも自分は、アンチパターン(の回避)こそがリファクタリングの指針としても優先されるべきだと思う。だからこそリファクタ本でも先にCodeSmell が語られていたはずだし。

さらに古い話だけど、コプリエンの『C++プログラミングの筋と定石』というのが出たときにも、イディオムの記述もさることながら、やってはいけない事について割と力をいれて書いていたのが、非常に有益だった(業界でもそれで高評価を得ていたような記憶があるし)。

こういう、アンチパターンへの感覚は、日常生活においての「格好いい事を主張する以前に、まずは人並みであるべき」という常識だとか、学歴やスキルの高さ以前に犯罪歴や暴力性向が無いことが前提とされたりする事のような、ごく当たり前の感覚にも通じていると思う(芸術家は別だけど)。

そんな自分の思いに反して、アンチパターン系の知識は、パターンやベストプラクティスが歓迎されるほどには省みられない。当たり前すぎて語られないのならまだしも、そもそも知られていなかったり、無視され、読み飛ばされてしまっている。減点方式っぽい思考法なので日本人に向いているような気がするけど、現実は逆だったりする。

それどころか、こういう割と普通の感覚が、既に動いているプロジェクト・チームに新たに参入した時に、場合によっては地雷を踏むきっかけになったりする。

アンチパターンを解消するには、まずはそれを発見する事から始まるが、上手くやらないと、上から目線であら捜しをしていると捉えられる。また、現行メンバの仕掛中作業を妨げないように、自分がリファクタリングや後付テストコード記述をするなんて申し出たりしても、自分だけ手を汚さずに当て付けがましい事をしているように見られる事もある。(もちろん「お前ら全員今からリファクタしろ」なんてストレートに言うと、さらに楽しくない状況になる。つうか、そんな事言えない。)

門外漢には、そんな子供っぽい現場は滅多にないだろうと思われるかもしれないが、プロジェクトが1年も続くといろいろな事があるし、特に一旦火を噴いてやっと沈静化しかけた頃のような現場だと、かなりのメンバの心の中に、大人でもなかなか笑って水に流せないトラウマがわだかまっていて、至るところ地雷だらけだったりする。

まあでも、自分が最近、途中から参入した現場はそんな危険な雰囲気も少なく、アンチパターン/ワーストプラクティス/コードスメルが大量にある割には、メンバの精神状態もおおむね良好で割と気楽なんだけど、それでも油断できない。上の人間は早く成果を出せと思っているっぽいが、やはりここは、ゆっくり慎重に行こうと思う。

本当に技術者ってデリケートなんだよなあ・・・

Typemock--コンストラクタの呼び出しチェックが・・・

テスタビリティの悪いシステムに後付のユニットテストを書く事になりそうなので、モッキング・フレームワークを検討中。

フリーの Moq やら何やらは、バーチャル・メソッドしかモックできないなんて制約があって、最初から最大限にテスタビリティを考慮したシステムにしか適用できそうにない。それ以前に、そもそも.net フレームワーク自体がテスタビリティを下げる犯人でもあったりして、悩ましい。

そんなこんなで、Typemock Isolator という有料のものを見つけて、個人ライセンスで試用しているが、どうやらこれしか選択肢はないらしい。静的メソッドや sealed までモックテストできたりする。

さすがに有料だけあって、非常に強力なのだが、ちょっとモッキングが難しいパターンを発見したのでメモしておく。
class Class1
{
    public string Name {get; set;}
    public Class1(string name)
    {
        this.Name = name;
    }
    public void ShowName()
    {
        MessageBox.Show(Name);
    }
}
class Program
{
    static void Main(string[] args)
    {
        Class1 class1 = new Class1(args[0]);
        class1.ShowName();
    }
}

上記のようなコードで、Main()メソッドの後付をテストコードを書くとすると、モックテストとしての要点は、
  1. Main()が引数の先頭要素を Class1 コンストラクタに渡している事を検証する
  2. 生成したインスタンスの ShowName()メソッドを呼ぶ事を検証する。
  3. 但し、実物の ShowName()は実際に呼ばれてはいけない。
というものになる。

ここで仮に、1)の要件が無いとすると、以下のような EDSL 風のコードで2)と3)をテストできる。
[Test, Isolated]
public void Test1()
{
    string[] args = {"arg1"};
    //Arrange
    var fake = Isolate.Fake.Instance<Class1>();
    Isolate.Swap.NextInstance<Class1>().With(fake);
    //Act
    Isolate.Invoke.Method<Program>("Main", new object[] { args });
    //Assert
    Isolate.Verify.WasCalledWithAnyArguments(() => fake.ShowName());
}

テスト対象メソッドの中で生成されるオブジェクトを、実行前に生成した贋物にすりかえてしまえるのが面白い。

ところが上記のような、Isolate.~~(AAA APIと言うらしい)を使う方法だと、要点 1)のコンストラクタにへの引数を検証するやり方がどうも見当たらない。

調べると、Typemockには AAA API の他に、より古いAPIセットがあって、こっちにはコンストラクタ引数の検証メソッドがあるという。
以下のようなコードで、要点1)を検証できる。
[Test]
public void Test2()
{
    string[] argument1 = {"arg1"};

    MockManager.Init();
    Mock theMock = MockManager.Mock<Class1>(Constructor.NotMocked);

    theMock.ExpectConstructor().Args(argument1[0]);
    theMock.ExpectCall("ShowName", 1);

    Isolate.Invoke.Method<Program>("Main", new object[] { argument1 });

    MockManager.Verify();
}
ところがTest1()とTest2()を、どうしても一つのテストメソッドにマージできない。
Test2()の古いAPIセットを使う方式だと、一個のメソッドで、1)~3)までテストする事もできない事はなさそうだが、陳腐化しはじめているし、そもそもTest1()のAAA APIが推奨されているし、やっぱり嫌だ。

上のような状況の後付テストを書くときは、1メソッドに対して2系統のテストを書く事になるのか・・・
それとも、AAA に未発見の API があるのか・・・
後者に期待したいが。

====
と言うかそれ以前に、これを使うとした場合、プロジェクトとして調達するためにステークホルダに説明しなければならない事として、
  • 現状のシステムのテスタビリティが低すぎる事。
  • モックテストとは何か、その必要性はどんなものか
  • 既存の書きかけのテストコードが、下手糞すぎて使えない事
  • functional test と unit test が混同されていたり(違いはここ)、何のテスト方針も定まっていない事
などなど、いろいろあって、そこから面倒くさい。

2010年6月21日月曜日

証券外務員2種合格

今日、プロメトリックで証券外務員2種の試験を受けて合格した。

勉強量は、休日を利用しての(10H~12H)×3日に、平日の空き時間の勉強を加えて40時間強くらい。日本経済新聞社から出ているノースアイランド編の問題集を使ったが、これより少し難しく感じた。ただ以前に取った簿記2級やFP2級と被っている出題範囲が多く、その分だけ楽だった。

取得目的は、いま携わっている開発案件が証券のシステムなので、その勉強のためだったけど、やってみると知識の範囲がかなり違っている事が分かった。開発中のシステムではユーザは証券会社のディーラーだけど、一方、証券外務員が相対するのは一般投資家だったりして、知識のジャンルが思いのほか大きく違う。まあ、証券業界人にとっては常識的な事柄ばかりだろうから、SI屋としても知っておいて損ではない情報なのだろうとは思う。

こんな感じで業務知識(とその資格)を貯めていって、そのうちドメインモデルの分析からちゃんとやりたいと思う。今の自分の状況だと、何というかIT色・オブジェクト指向色の濃い、アーキテクチャ周りの仕事を受け持つ事が多くて、自分がフレームワークを選定したりアーキテクチャを考えているうちに、いわゆる業務系SEとかいう人達が、何の分析も何の洞察もないまま体裁だけまとめた「設計書」を作っちゃっていたりする。

「業務知識なら割と自信がありますよ」なんてサラっと言えて、その証明らしきものも提示できる様になれば、ドメイン分析の担当に志願しても、それほど反対される事はないのではないかと思う。

2010年6月14日月曜日

The Test Smells

xUnit Test Patterns』 に載っている、CodeSmell の xUnit バージョン。

どうもこの本は、まとめ方が若干惜しい。掲載されているテストのノウハウは、量も多く網羅的で、プログラマなら(特にプログラマのリーダ的な立場の人は)、知って置きたいテクニックが満載なんだけど、見せ方がいまいち。

自分は、特に「Test Smell」のパートがこの本の中でも重要な部分だと思っているけど、ここも違和感がある。一個の Test Smell のカタログ項目として、複数の Causes(原因)が列挙されているが、これら自体が Test Smell だったりして、何だかややこしい。

以下のような Test Smells が掲載されている。
  • Project Smells
    • Production Bugs:
      公式なテストで(開発チームの手を離れてからのテスト)、または出荷した後に見つかるバグが多すぎる
    • Buggy Tests:
      テスト自体にバグが多い
    • Developers Not Writing Tests:
      テストコードが書かれていない
    • High Test Maintenance Cost:
      メンテするのが大変すぎる
  • Behavior Smells
    • Fragile Test:
      テスト対象コードに含まれない、他所の部分の改修によって、テストが通らなくなる
    • Assertion Roulette:
      テストメソッド中の、どのアサーションが失敗してるのか分かりにくい
    • Erratic Tests:
      その時々で、あるテストが通ったり通らなかったりする
    • Frequent Debugging:
      テストが通らない原因が、いちいち手動デバッグしないと分からない
    • Slow Tests:
      テストの実行に時間かかりすぎる
  • Code Smells
    • Obscure Test:
      何がどうなる事を検証しているのかが不明瞭
    • Conditional Test Logic:
      テストロジックの中に条件分岐があって、場合によって実行パスが通ったり通らなかったりする
    • Hard-to-Test Code:
      テスト対象コードのテスタビリティが低すぎて、テストが書けない
    • Mannual Intervention:
      いちいち手作業で何らかの介入をしないと進まない
    • Test Code Duplication:
      テストコードが重複している
    • Test Logic in Production:
      製品コードにテストコードが含まれてしまっている

xUnit に慣れているプログラマなら、上記のほとんどの Test Smells について、常識だと思うかもしれないけど、熟練者がいないチームで暗中模索しながら書かれたテストコードなんかだと、かなりの頻度で遭遇するアンチパターンだったりする。

2010年6月9日水曜日

Concurrency patterns

並行/並列実行とかマルチスレッドのパターンの情報源。

まずは POSA 第2巻。並行とネットワークのパターン集から。
Pattern-Oriented Software Architecture, Volume 2, Patterns for Concurrent and Networked Objects
Pattern-Oriented Software Architecture, Volume 2, Patterns for Concurrent and Networked Objects


直接的には、「Concurrency patterns」 にカテゴライズされている以下のパターン。
  • アークテクチャ・パターン
    • Half-Sync/Half-Async
    • Leader/Followers
  • デザインパターン
    • ActiveObject
    • MonitorObject
    • Thread-Specific
また、関連するカテゴリとして「Event Handling Patterns」と「Synchronization Patterns」があり、以下のような内訳
■ Event Handling Patterns
  • アークテクチャ・パターン
    • Reactor
    • Proactor
  • デザインパターン
    • Asynchronous Completion Token
    • Acceptor-Connector
■ Synchronization Patterns
  • デザインパターン
    • StrategiedLocking
    • Thread-SafeInterface
    • Double-CheckedLockingOptimization
  • C++ イディオム
    • ScopedLocking

上述のパターン群のうち多くは、下リンクの『パターン言語』でも、分散・並行化設計パターンのパートに含まれている。
プログラムデザインのためのパターン言語
プログラムデザインのためのパターン言語

ただし POSAv2 に無い、以下のパターンも含まれている。
  • ObjectSynchronizer
  • ObjectRecovery
  • Bodyguard


.NET 4.0 の Parallel Patterns というものもある。以下のリンクから C# 版とVB 版 がダウンロードできる。
PATTERNS OF PARALLEL PROGRAMMING
  • Delightfully Parallel Loops
  • Fork/Join
  • Passing Data
  • Producer/Consumer
  • Aggregations
  • MapReduce
  • Dependencies
  • Data Sets of Unknown Size
  • Speculative Processing
  • Laziness
  • Shared State
実はさっき見つけたばかりで、まだ読んでいない。C# の仕事をする事になりそうなので興味深いが、現場では多分 .NET 3.5 を使う事になりそうな模様。

2010年6月7日月曜日

mocking の要点

モックを使うと何がどう変わるかを、単なる assertion と比較して考えてみる。

例として、以下のような testTarget のテストを考える。testTarget オブジェクトは foo() 呼び出しの中で、collaborator の bar() を呼び出す。この testTarget → collaborator の関連は、クラス図や CRCカードにも明記されるような、れっきとしたクラスの仕様であるとする。

これを xUnit の昔ながらの assertion でテストすると、下図に示すように、テスト・コード管理下に入るのは foo() 呼び出しの条件と結果となり、カバレッジに含まれるのは赤の網掛けの部分となる。

ここでまずい点が三つある。

① testTarget と collaborator の協調がテストされていない。collaborator を正しい条件で呼び出しているか、また得られた結果を正しく扱っているかが検証されない。(それどころか、collaborator を呼ばないダミーコードが実装し忘れたまま残されていたとしても、テストコード側では認識しようもない。)

② テスト対象外のコードまでがカバレッジに含まれてしまっている。collaborator のコードは、collaborator のテストコードが書かれて始めてカバレッジに含まれるようにしないと、網羅率が正味のテスト実施状況と乖離してくる。テスト漏れも生じやすくなる。

③ collaborator の bar() を実行するために、リソースやらコンテナやらのセットアップが必要な場合、テストコードが煩雑になる。また多くの場合、テストの実行速度も物凄く遅くなる。

これに対し、xMock を導入して assertion と併用すると、上述の問題が改善できる。

上図は collaborator をモック化した場合のもの。collaborator 呼び出しの条件がちゃんと検証され、返される結果もテストコードからコントロールできるようになる。カバレッジはテスト対象コードのみとなり、リソースをセットアップする手間もなくなって実行時間も早くなる。

デメリットがあるとすれば、テクニック的に assertion よりは若干難しい事くらいだろうか。他のクラスとの協調も検証対象になる分、書かなきゃならないテストコードの量が多くはなるが、本来テストすべきだった事ができるようになっただけなので、別にデメリットという事にはならない。

PMBOK と waterfall

ソフトウェア業界にいていろんな人と会話する中で、たまに PMBOK の話題になるが、PMBOK とはウォーターフォール型開発のためのプロジェクト管理手法であって、アジャイル系のプロセス・モデルには馴染まないと思っている人が結構多い。

そもそも PMBOK は、ソフトウェア開発のための知識体系ですらないけど、まずそこからして誤解が多い。

ちなみに、手元の PMP の参考書に載ってるケーススタディを適当に抜き出すと、
  • オリンピック支援チームを収容する建物の建設プロジェクト
  • 映画製作のプロジェクト
  • 郵便局に新しい料金システムを導入するプロジェクト
  • 高速道路を拡幅するプロジェクト
とかだったりする。ソフトウェア開発に限ったものでは全くないし、ましてウォーターフォールとか、なおさら関係ない。

(もしかすると PMBOK 関連の記事をチラ見して、「立ち上げ、計画、実行、監視コントロール、終結」からなる5つのプロセス群に、ウォーターフォールのフェーズ「要件定義、設計、実装、テスト、移行」を勝手に脳内マッピングしちゃったりしてるのかも。)

だからと言ってアジャイルに親和性が高いのかというと、そう言うわけでもない。結局、相当の応用力が要求されるという点では、どんなプロセスモデルを採用しようと変わらない。例えば経営学という知識体系が、どんな会社の経営を対象とするのか問題にしていないのと似ていると思う。

ただし、アジャイル開発者が PMBOK を勉強するのをためらっている理由が、冒頭に書いたような誤解だとしたら、決してそんな事はないので、お勧めしておきたい。プロセスについて日頃から考えている人ほど、面白く感じられると思う。

2010年6月6日日曜日

Systems thinking のパターン

システム・シンキング入門』という本で、「システムの原型」として把握される5つのパターンが紹介されている、。ソフトウェア開発プロジェクトの分析にも、大いに使えそうなので、以下にまとめておく。

■ 応急処置の失敗
・対症療法が予期せぬ悪影響を発生させて、問題が悪化していく因果ループ
・分類:悪化ループ

開発現場で実によく見かけるもの。例えば「時間が無い」という「問題」に対して、「応急処置」として何かのタスクを省略したりすると、大抵このパターンにはまって後で大変な事になる。

あと切羽詰ったプロジェクトで、下手に増員して却って火に油を注ぐのも、ほぼこのパターン(ほんの少し構造が違うが)。

■ 問題の転嫁
・対症療法による目先の効果により、本来必要な根本的対応が先送りされてしまう因果ループ
・分類:悪化ループ
これもよくある。例えば、「根本的な解決策」がアーキテクチャの変更を伴うような場合に、重い作業を避けてベタな暫定対応に逃げたりすることが良くあるが、やればやるほどコードのメンテ性が低下して、抜本対応が遠のいていったりする。

■ エスカレーション
・双方の行為が脅威となって、互いに行動をエスカレートしていく因果ループ
・分類:悪化ループ
システム開発プロジェクトでは、意外と見ないかも。ちょっと思いつかない。現実の社会では、軍拡競争など、分かりやすいサンプルが豊富。

■ 成功の限界
・拡張プロセスがバランスプロセスに変化して、勢いを失い進歩が止まる因果ループ
・分類:停滞ループ
リファクタリングが実践されていないチームでは、機能追加/変更によるアプリケーションの成長の陰で、重複コードの増殖やメソッドの長大化により変更コストが増加して、結局アプリケーションの成長も鈍っていく事になる。開発者なら分かりやすいパターンだと思う。

あと、組織やユーザが大きくなればなるほど、それ自身の重さが進化を鈍らせるという点では、昨今、Java がパターンにはまっているような気がしないでもない。

■ 成功が成功を生む
・両立すべき事柄の一方での成功が、他方に一層の失敗をもたらす事になる因果ループ
・分類:悪影響ループ

Java と .NET の間で、このパターンが生じる事がある。Java にも .NET にも、それぞれ長所短所があるので、合理的に使い分けられるのが理想だけど、ある局面での Java の選択は、Java 技術のスキル向上を促す一方で、.NET 技術の スキル低下を引き起こす事にもなり、次の局面での Java の選択圧力を強める。これがループして、Java/.NET 間の格差が一定限度を超えると、.NET を使えば低コストに開発できるような場面でも、スキル的に Java しか選択できなくなったりもする(逆も成立する)。結構、優秀な技術者でもこうなってる人が意外と多い。

====
アンチ・パターン/プラクティスのうち、プロジェクト管理や開発プロセスの領域に該当するものは、Systems Thinking の方法を使うと統一的に現象を記述できるような予感。因果ループ図を取り入れて、アンチ・パターンのカタログを再編集してみるのも良いかも。

2010年6月5日土曜日

ブラック・ショールズ方程式の解のグラフ

wikipedia のブラックショールズ方程式の解の式をグラフ化してみる。

以下の条件で、
権利行使価格(K)110
安全利子率(r)0.07
ボラティリティ(σ)0.2
期間(τ=T-t)0.25
横軸にとった原資産価格に対するコールオプションプレミアムの適正価格を、Excel で折れ線グラフにしたものが下図。


原資産価格110のところがアットザマネー(ATM)で、左側がアウトオブザマネー(OTM)、右側がインザマネー(ITM)ということになる。OTMからATMに近づく辺りで上昇し始めて、ITMではK・exp(-rτ)≒108 から右上45℃に延びる線に漸近する形になる。

式だけ見ても全然想像がつかないけど、グラフに描いてみるとなんとなくイメージがつかめる。正規分布なんかでも、誰でもそのグラフ形状ならしってるけど、式自体は結構難しかったりするし。

2010年6月3日木曜日

usecase の本

久しぶりに仕事でユースケース書く事になりそうなので、以下に手持ちのユースケースの資料を整理。

Writing Effective Use Cases
Writing Effective Use Cases

言わずと知れたユースケースライターのバイブル。読めば読むほどユースケースを書く作業が面白くなってくる。書いているうちに沸いてくる疑問や迷いについても大抵答えが提示されている。

実用的には、とりあえずこの一冊があれば十分じゃないだろうか。チームで作業するときも、この本から要点を抜き出してガイドラインにして配布するようにすればいい効果が期待できる。

Patterns for Effective Use Cases
Patterns for Effective Use Cases

内容は『Writing Effective Usecases』に載っている事がほとんどだけど、パターンカタログの体裁をとっているので、そういうスタイルが好きな人には良い本。

Applying Use Case Driven Object Modeling with UML
Applying Use Case Driven Object Modeling with UML

タイトルからは分かりにくいけど、ほぼ ICONIX というアジャイルプロセスの解説書。
ICONIX では ユースケース が重要視されていて、他の成果物やタスクとも絡んだプロセス全体の中での活かし方とか位置づけとか、結構参考になる。他に、Domain Model や Robustness 分析についても上手に解説されていて、なかなかの良書。

ユースケースによるアスペクト指向ソフトウェア開発
ユースケースによるアスペクト指向ソフトウェア開発

ユースケースの開発者のヤコブソンが、アスペクト指向をとりこんで発展させたもの。

アスペクトって、ログとかトランザクションとか実装レベルかつ非機能要件の領域で語られる事が多いけど、もっと高い抽象度でドメインよりの話題としても語られても良いのではなかろうかと思ってるときに見つけた本。

と言っても実は、正直まだよく理解できていなかったりする。上の3冊はサクサク読めて現場でもすぐに役立てられる本だけど、この本はある程度時間をかけてじっくり読む必要がありそう。

====
他にも何冊か UML の参考書があって、中でユースケースにも触れられているけど割愛。なんかユースケースのスティックマンのおかげで、ユースケース本来の重要性が見失われ続けている気がしないでもない。

2010年6月2日水曜日

プロジェクトの英語化

楽天で英語が社内公用語になったらしい。[→この記事]

この施策が、事業の国際化に正味どれだけ貢献するか知らないけど、技術者としてはちょっと興味深い。例えば、システム開発プロジェクトへの英語の導入を想像してみたくなるが、ちょっと思案してみると、まんざら不毛なアイデアでもなさそうな予感。期待したいのは、国際化なんかじゃなくて、システム開発を合理化したいという、それだけなんだけど。

まあ、進捗会議やら朝会やらでの英会話は無理っぽい。「日本人は読み書きはできるが会話は苦手」なんて言われてもいる程だし、とりあえず読み書きのみの英語化にとどめて良いと思う。


話を簡単にするために、自社で販売するパッケージ製品の開発や、英語でコミュニケートできるクライアントのための開発を想定して、クライアント組織の言語はとりあえず考えなくて良い事にすると以下のような感じだろうか。

☆ まずユースケースの英語化。これが最も効き目の大きなところだと思う。

そもそもオブジェクト指向においては、要件定義に現れて来るドメインの語彙が、そのまま 名詞 ⇒クラス名、動詞 ⇒メソッド名という形でソースコードに直接的に投影されるという事が重要で、同時に開発者が留意すべき点でもあったはず。プログラム中の識別子の語句と、ユースケース/ドメインモデルの語句が同一である事が、内部品質(≒保守性≒生産性)にも大きく貢献していたのだと思う。

ところが日本のプロジェクトでは、日本語の上流成果物から英語ベースのソースコードに至る過程のあちこちで、脳内和英変換でエネルギーを浪費させながら作業する羽目になる。あまりに常態化しているのでなかなか反省されにくいが、洋書に載っているような演習やケーススタディ、つまりユースケースにもソースコードにも共に英語を使っているものと比較すると、明らかな不経済だと分かる。

やはりまずは英文ユースケースが欲しい。投入すべき労力も大きそうだが、得られる見返りも大きいと思う。

☆ で次に、ユースケースが英語化できたら、ソースコードに至るまでの中間的なドキュメントも、やはり英語化。まあユースケースが英語になった時点で、後続の成果物の英語化も大分楽になってるはず。ハードルは低いと思う。

JavaDoc 等のいわゆるヘッダコメントも英語で記述。当然ながら、識別子に用いられるコトバと、その説明に用いられるコトバは統一されている方が、別々の言語からとった語をそれぞれに適用するよりも合理的と思われる。

ソースコメントについては、昨今の流儀では「コメントを書いている暇があったら、コメント無しでも読みやすいコードを書くよう工夫すべし」とされているが、英語を意識して開発できるようになれば、各ステートメントが英文ライクな構造に、自然とフツーに近づいていくはず。まあ、どうしてもコメントを書くなら英語で書くべきだろう。

☆ その他の英語化対象としては、WBS、スケジュール表といったところか。
Trac のチケットや wikiも英語化によるメリットがありそう。

====
てか、そもそも普段使っているプログラミング言語のキーワードや API の識別子のほとんど全てが、英語話者が何百年も前から使っている人間の言葉だったりする。それに文法の面でも、大抵のオブジェクト指向言語では、なんとなく英語構文の語順を意識している節がある。
(SVO と subject.verb(object) みたいな)

こういう事を考えると、なんだか全面的に英語で開発するというのがプログラミング本来の姿なのではという気さえしてくる。

なんていろいろと書いたが、現実のIT業界では「会話はできないけど読み書きはできる」という前提からして、まず怪しかったりする。そこそこ読み書きできる開発メンバを集めるだけでも、実は大変かもしれない。

2010年5月30日日曜日

証券のアナパタ

証券の仕事をする事になりそうなので、ちょっと準備。

以下、アナリシス・パターンから関連するものを抜粋。

Contract 取引契約 (9.1)
単純な Contract モデルから、ロング/ショートの扱いに着目したいくつかのバリエーションまで解説

Portfolio ポートフォリオ (9.2)
Contract の集合としての最も単純な Portfolio モデルから始めて、Contract Selector、Portfolio Filter を用いた発展型まで解説

Quote 呼び値 (9.3)
bid と offer の二つの属性からなる Quote について解説

Scenario シナリオ (9.4)
Quote に Timepoint を関連付けた原始的なモデルから始めて、ある時点の Quote の集合を表す Scenario モデルの単純な版を経て、Sourcing や Fomula まで含めた発展形のモデルまで解説

Forward Contracts 先物取引 (10.1)
Contract に Tenor を付加したモデルで先物取引を表現

Options オプション取引 (10.2)
Contract のサブタイプとしての Option モデル。Long/Short、Call/Putの扱い方など。

Product 加工商品 (10.3)
Options の合成を、Straddleを例にして解説


その他、以下のような関連箇所もある。
  • 「Subtype State Machines(10.4)」では、デリバティブの動的な面を、ステートマシンを用いて解説している。
  • 「Parallel Application and Domain Hierarchies(10.5)」では、アーキテクチャ面について、Layerd Structure に関連づけて説明。
  • また11章では、パッケージ分けしたドメインモデル(DDDで言うモジュール)を扱うための各種技法を紹介。


アナリシス・パターンを最初に読んだのは2000年頃なのでもう10年も前になる。ある程度証券の知識を得た今読み返すと、当初感じた難解さがそれほど感じられない。

最近 Domain-Driven Development(DDD)についても調べているけど、Layered Architecture などを中心にアナパタからの影響が多くみられる。ただし DDD はドメインモデルのパターンではなく、モデルを抽出する過程に着目したプラクティスという性質がむしろ大きい。

設計のパターンの場合は、ある課題の解としてパターンを「適用する」というか「当てはめる」といったような使い方になるけど、アナパタはモデリングの出発点・たたき台として使うのが良いのだと思う。

2010年4月27日火曜日

Swordfish の GettingStarted 試行

久しぶりに Eclipse のサイトを見てみると、Eclipse の新しい SOA Initiativeが発足したと言う、04/21 付けのアナウンスがあった。リンクをたどると、こんな Webinar を見つけたので早速やってみる。

以下のような内容
  • 00:00 part 1 Swordfish の概要と準備
  • 05:55  target platform の設定方法
  • 06:46 part 2 サンプル作成
  • 08:15  step 1 FlightReservation Provider
  • 13:53  step 2 PaymentProcessing Provider
  • 16:40  step 3 FlightBooking Provider
  • 24:25 part 3 Service Registry の使用
  • 29:10 結び

思い切り端折って言うと、OSGiベースで"分散ESB"を実現するための仕組みと、Eclipse によるサポート。Java 的には、DI に Spring、Webサービスには CXF を使っている。

SCA ではないけど、このチュートリアルでもコンポジットという考え方を採用している。既存の Webサービス(Provider)に対して、これを用いる Consumer を定義し、それらを部品とする上位のサービスをコンポジットとして定義するような方式。

ちなみに、この Getting Started も WSDL ファースト。昔は Javaコードを書いてから Webサービスで公開って流れのチュートリアルもあった気がするが、最近は見かけない。WSDL ライティングについても、チーム内で共有できそうなベストプラクティスとアンチパターンを見繕っておいた方が良さそう。

2010年4月26日月曜日

BPEL×AntiPatterns

以前のポストでは CodeSmell の BPEL への適用を調べてみた。同じ要領で、AntiPatterns の「ソフトウェア開発のアンチパターン」について、一個一個考えてみる。

尚、★印は5段階に分類した要注意の度合いで、発生頻度×影響度って感じ(感覚ベースの脳内統計だが・・・)。

■ Spaghetti Code ★★★★★

BPEL の言語的性質から、実行パスがもつれたり絡んだりする事はそれほど無くて、古典的な意味でのスパゲティにはならないが、グローバル変数がらみの広義のスパゲティになる事が多い。

グローバル・スコープに変数を定義して、複数のアクティビティで上書きしながらワーク領域として使いまわしているコードがあったりすると、可読性が落ちるわ潜在バグの温床になるわで、生産性と品質の両面に大きなダメージがある。


■ The Blob ★★★★
オリジナルは、与えられた責務が多すぎてオブジェクトが肥大化している状態を言うが、BPEL でもプロセスが長すぎて困るのは良くある。

長いからその分いろんな改修や仕様変更の影響を受けやすく、複数担当者で作業対象がカブる率が高くなり、生産性にかなり悪影響がある(担当者のアサインの仕方にもよるが)。

改善のためには BPELコーディングの面よりも、主にプロセス設計の面からのアプローチが有効と考えられる。例えば、プロセスを分割するとか、サブプロセスとして別サービスに括りだすとか。
■ Functional Decomposition ★★★★
オリジナル AntiPatterns では、オブジェクト指向開発なのに非オブジェクト指向で書かれたコード、例えばポリモーフィズムを使うべきところで if文や switch文を使っているなどの悪習を指す。

言語の本来の性質や目的に合っていないコーディングという意味では、BPEL の場合だとサービスのオーケストレーションに寄与していないコードが怪しい。例えば<assign> しか含まないループや分岐は、BPEL ではなく XSLT で書くべきケースが多い(書き易さの面でも)。
■ Cut-and-Paste_Programming ★★★★
BPEL でも重複コードは頻出で、やはり大体コピペで作られる。ただし BPEL 自体、小さなサブルーチンに細かく分割するのに向いてる言語ではないため、普通のALGOL系言語より重複しやすい。

そういった仕方の無い面もあるにせよ、やはり度が過ぎると、たった一つの変更が何十個所もの改修に及んだりしてダメージが大きいため、できるものなら解消したい。

やり方は、xpath 関数を拡張するとか、XSLT に切り出して再利用するとか、プロセスの一部を別サービスに切り出すなど。いずれのやり方も自明でも無いし常に適用可能でもないので、工夫と妥協が必要。
■ Input Kludge ★★★★
都合の良い入力条件でしかまともに動かないプログラムを指したアンチパターン。

オブジェクト指向開発だと xUnit や TDD が高度に発達して、既にかなり普及しているけど、それらのノウハウを BPEL に適用するのは現状ではなかなか難しい。入出力XMLデータの検証くらいは簡単にできるけど、途中の Web サービスとのやり取りまで含む検証は、意外と手間がかかるしシナリオの想定も難しい。

あと厳密に Input Kludge に該当するか分からないが、開発環境で本物の Webサービスの代わりに使うスタブでも同様の問題が生じる。スタブ化しようとするサービスのドキュメントの不備や解釈のブレによって、なかなか実物のサービスと開発者の想定が一致しない。で、スタブでは動いたが実サービスを繋いだテストでは不具合が出るということになる。

プロジェクトの性質によって対処法はまちまちだろうけど、なるべく早いフェーズでテストと実装(特にスタブ)の戦略は立てておく必要がある。


■ Lava Flow ★★★
使われなくなったコードのことで、デッドコードとも言われる。仕様変更の対応などに伴って BPEL でもよく発生する。あるBPELプロセスの全体、またはその部分、或いはBPELから使用している*.xslファイルや*.xsdファイルなどが、いつの間にか使われなくなったりする。

これについても、無駄なメンテナンスが発生するので、なるべく早く削除すべき。(ちなみにコメントアウトして残す癖のある人もいるが、良い習慣ではない。)
■ Golden Hammer ★★★
オリジナル AntiPatterns では、ある特定の解法や技術を何にでも盲目的に適用してしまう事を指す。ややキツ過ぎる言い方になるが、日本語だと「バカの一つ覚え」ってところだろうか。

BPEL 開発でも、知識が足りないまま作業開始して手探りで進めているようなプロジェクトで、頻繁に生じる。過去に見かけて印象に残った例だと、BPEL外部の XMLファイルの内容にアクセスするために、標準 xpath 関数のdocument() を使えばいい事を知らずに、無理やり orcl:lookup-xml()を使っていたコードなどがあった。
■ Ambiguous Viewpoint ★★★
分析の視点と実装の視点の混同、特に分析・設計時に実装の問題を混入させてしまう事を指す。

BPELの場合、OO言語を用いた開発に比べて、実装に先立つ設計作業の比重が大きかったりするが、ここでワーク変数の扱いだとかデータ加工の具体的ロジックなどまで含めてしまうのは、本当に百害あって一利なしなのでやめるべき。


■ Continuous Obsolescence ★★
準拠する仕様や基盤となる製品のバージョンアップにともなって、既存コードが絶え間なく陳腐化していく現象を指す。BPEL開発 の場合、まず BPEL、XSLT、XPATHといった標準仕様、またそれらについて各製品独自に拡張した部分、さらに 基盤となる BPEL/SOA 製品などについて、各々、時間の進行に伴ってバージョンが上がって行く事になる。

まあ、そもそも疎結合が SOA の謳い文句なので、外部サービスのバージョンアップの影響は余り受けずに済む。サポート期限などは別にして、陳腐化についてはそれほど神経質にならなくてもいいかも。

尚、開発を始める段階でなるべく新鮮は最新版の製品を使えば、陳腐化までの時間を長引かせる事はにはなるが、下記の Walk through a Minefield には注意する必要がある。
■ Walk through a Minefield ★★
リリース後間も無い未知のバグを含む新製品を採用して、問題解決に困ってしまうというアンチパターン。

これは発生頻度もダメージも、プロジェクトや製品ごとにまちまち。対策としては、プロトタイピングとか、反復型プロセスで早期に問題を燻り出したりとか、まあ普通のリスク回避策しかないか。開発に取り掛かった時点で「枯れている」製品を選ぶのも一つの手だが、これも気をつけないと陳腐化リスクが大きくなる。
■ Poltergeists ★★
存在意義があまりないクラス。

BPEL の場合だと、例えばサービスを一個呼ぶだけのプロセスなど単にコンポジットから呼び出せば済むような、オーケストレーションが無いプロセスはこれに当たると考えられそう。
■ Mushroom Management ★★
エンドユーザから隔離されたデベロッパが、十分な要件定義も与えられないまま、想像でコーディングするしか無い状況に追い込まれること。まあ BPELに限らずシステム開発プロジェクトの初歩的な問題なので割愛。


■ Boat Anchor ★
現在の開発対象システムには不要と思われる贅沢な機能を満載したソフトやハード。

単にお金が掛かるというだけなら、自分の金じゃないし払う方の勝手だけど、そのために本当に必要なリソースが圧迫されるとしたら、PM かステークホルダに具申する必要がある。

また OSS の軽量な製品で事足りるのに、重すぎて扱いにくい商用製品が使われてたりすることもよくある。開発端末ではありえないレベルの高スペック・サーバマシンじゃないと動作しないような BPEL 製品だとか、そういうのは本当に生産性が落ちるから、極力避けたい。
■ Dead End ★
他所から入手した再利用コンポーネントを部分変更した後、サポートを受けられなくなってしまうこと。
まあ、あまり起こりそうに無いし、気にしなくてもいいか。

2010年4月24日土曜日

Galileo/ODE/Tomcat

Eclipse の BPEL Plugin と ODE の併用メモ。

2010年4月時点での最新の環境を使いたいが、ネット上の既存のチュートリアルは Ganymede のみ対象だったり、度々発生するエラーの対処法がなかったりするので、ちょっと整理しておく。

■ 環境
  • Tomcat 6.0.2
  • Eclipse 3.5 Galileo
  • ODE 1.3.3

■ BPEL Plugin
Eclipseの[Install New Software]で、アップデートサイトに以下のURLを指定してプラグインを追加。
http://swordfish-tooling.googlecode.com/svn/trunk/org.eclipse.swordfish.third-parties/bpel/

インストール中に javax.wsdl が足りないって言ってきたら、Eclipse のplugin フォルダに以下の 3つの jar を入れてやり直し。(既にあるものは、それでOK)
2010/04/27 追記
eclipse-rcp-galileo-SR2-win32 (Eclipse 3.5.2) をベースにすると、上記エラーは発生しない。また上記の javax.wsdl*.jar を追加する方法だと、後で partner link を定義するときに別の問題(LinkageError)が発生する可能性があるが、最初からEclipse 3.5.2をベースにしておけば、この問題も回避できる。

注) 以下のURLのアップデートサイトは Eclipse 3.4でしかうまく動かない。
http://download.eclipse.org/technology/bpel/update-site/

以下、参考にしたサイト
■ ODE WAR版
ODE 1.3.3の war版をダウンロードして、zip の中身の ode.war を Tomcat の webapps下に置く。

Tomcat を Eclipse の Server Runtime として動かしている場合、ode.war の置き場所は以下のようになる。
{ワークスペース・フォルダ}\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\webapps

ここに置くと、勝手にデプロイされてodeフォルダが生成される。

■ デプロイ
developerworks の記事[→リンク]に、HelloWorld の BPEL版の作成からデプロイまで説明している部分があるのでやってみる。上述の作業が問題なくできていれば、Eclipse の Web Service Explorer で "Hello World" が返ってくる。

ちなみに BPELを更新したら、*.deployed ファイルを消すと再デプロイされる。

■ 雑感
  • ODE は WS-BPEL 準拠という事で、なかなか記述性が高く読みやすそう。上の HelloWorld でも "$input.payload/tns:input"みたいな書き方をしている(BPEL4WS 系ならgetVariableData()を使ったダラダラした記述になる)。
  • 商用のBPEL製品に比べると、やはり機能的にあっさりしすぎの感もある。特に監査情報がブラウザから見られないのは、開発時辛いかも。
  • 逆に機能がスリムな分、使用感が軽そうなのは良い。特に各開発者のマシンに一式インストールして動かせそうなのは良い。無駄にでかすぎる商用製品だと、結局1台の高スペックマシンに BPEL エンジンを載せて全員で共用したりする羽目になって、却って生産性が酷い事になったりする。
  • 後は、SCA、JBI、EIP 製品との組み合わせか。他のサービスといかにうまく連携させるか、アーキテクトの腕によるところが大きくなりそう。

2010年4月23日金曜日

BPEL×code smell

BPELコードの良し悪しを判断するガイドラインぽいのが無いかと探してみたが、これと言った物が見当たらない。こんな時に一から自分で考えるのはたいてい愚策なので、既存のものを叩き台にしてみる。

特に「良し悪し」の「悪し」の判別に役立つもの、つまりアンチパターンが欲しいので、まずは Refactoring に載っている CodeSmell を検討してみる。BPEL がオーケストレーション言語であるのに対して、CodeSmell は 主に OOP分野の話だから、そもそも異質ではあるけど、まあ業界の常識だし自分でもよく知っているので出発点としては適当。そんなわけで、Refactoring に載ってる 22個の CodeSmell から、BPEL でも当てはまりそうなものをピックアップしてみる。

============
まずは、CodeSmell がもたらす開発作業への悪影響が BPEL でも大きそうなものから

■ Duplicated Code
一般に CodeSmell の最たるものされているのがこの「重複コード」。BPEL 開発でも頻出で、例えば複数のプロセスで共通的に使う変数の初期化コードだとか、フォルト・ハンドラだとかがコピペで書かれると、この CodeSmell が生じる。

ただし、普通のALGOL系OO言語ならば、小さな重複を1~3行程度の小さなメソッドに切り出すような"mercilessly" なリファクタリングもいたって普通だけど、BPEL はそういうの向いてない。例えば、同じ<assign>アクティビティが重複しているからといって、「別プロセスに切り出して」なんてのは無理があるので、多少の重複は仕方なかったりする。

それでもやっぱり何とかしたいとなったら、こんな回避策になるだろうか
  • XSLT で書けるような重複ロジックは *.xsl ファイルに切り出して、<assign>中の doXslTransform() で実行する
  • Xpath 式に組み込めそうな部分で、且つ、使っている BPEL 製品 がXpath 関数を拡張 する仕組みを持っているなら、BPELエンジンに組み込んでXpathから字呼び出す。

■ Long Method/Large Class
BPEL だと長すぎるプロセスがこれに相当するだろうか。

原因には、プロセス設計の問題とコーディングの問題の2つの側面があると思う。前者なら例えば、本来は2つ以上の連続するプロセスを一本のものとして捉えてしまっている場合などで、後者なら、重複コード等、他の CodeSmell によるBPELコードの肥大化などが考えられる。

まあ、一見長すぎに見えても妥当なプロセス設計も当然あるはずなので一概には言えないが、ただし肥大化の原因が以下のような場合、解消の必要がありそう
  • 重複コードや不要コードなど、他の CodeSmell によるプロセス肥大化
  • BPELプロセスで、ループや条件分岐を含むデータ加工をしている。

■ DivergentChange/ShotgunSurgery
変更の影響に関する二つの CodeSmell。

DivergentChange はあるプログラム要素(クラスとかメソッド)が、いろんな種類の仕様/設計変更から影響を受けすぎているというもの。ShotgunSurgery は逆に、一つの仕様/設計変更が、余りに多くのプログラムの部分に影響を与えているというもの。

前者は BPEL での例がちょっと思い浮かばないが、後者の ShotgunSurgery は、例えばプロジェクト共通のフォルトハンドリングの方法が変わって、それに準拠している全てのプロセスの faulthandler を書き直すようなケースで、現場でもよくある。

■ Lazy Class
BPEL でも、仕様変更に対応してるうちに、あるプロセスが使われなくなったりする。また、プロセスが使っていた XSLT ファイルや XMLSchema ファイルなども同様のことが起こる。これも無駄な保守コストがかかるのでまずい。

■ TemporaryField
オリジナルの CodeSmell は、特定の状況でしか使わないデータを、メソッド・パラメータとかローカル変数ではなく、インスタンス変数にしちゃってるというアンチパターン。

BPELプロセスだと、局所的に使うだけの変数をグローバルに宣言したりして、無駄に広いスコープを与えているコードがこれに近いと思う。(IDE によっては、変数を宣言する時にデフォルトでグローバル変数にしているものがあり、結構良く見かける。このグローバル変数を使いまわしたりすると、本当にひどい難読コードになる。)

変数のスコープはなるべく短くすべしという基本は、やはりBPELでも成り立つと思う。

■ Incomplete Library Class
オリジナルは、いまいちニーズを充足しきれていない、惜しいライブラリを指す。BPEL でいうとベンダ独自の拡張機能あたりにそういう事があるかもしれない。

■ Comments
諸説あるが OOPでのコメントのつけ方の有力なガイドラインとして、メソッドの頭のコメント(JavaならJavaDocコメント)だけ書いて、メソッドの中では原則コメントを書かず、コメントなんかを書く労力をコメント無しでも理解しやすいコードを書くことに向けるべしというのがある。

ただ BPEL の場合、コードだけ(たとえばアクティビティの命名の工夫とか)でそれをやるのは難しいので、無理せずコメントを書いた方が良い場合が多いかも。(もちろんコメントがなくても分かるように書けるならそれにこしたことはないが。

============
以下、敢えて書こうと思えば書けるけど、実際には発生しにくそうな CodeSmell

■ SpeculativeGenerality
「現状で必ずしも必要ないが常識的に考えて必要だろう」というノリのコーディングを指す。YAGNI 違反という事になって、KISS原則にも抵触するからまずい。

BPEL だと余り無いような気がするが、敢えてそういうコードを書こうとしたら多分書けてしまうので、人によってはこういうの多いかも。

■ Alternative Classes with Different Interfaces
入力か出力の型が違うだけの理由で別々の BPEL プロセスを書いたりしたら、このCodeSmellに該当するだろうか。ただしサービスとして BPEL を呼ぶ前に XSLT で変換するようにすれば良いだけなので、実際にはなさそう。

■ MiddleMan
まあ他のBPELプロセスを呼ぶだけのBPELプロセスなんて、誰も書かないだろうけど、不可能ではない。


============
以下、あまり BPEL と関係ない CodeSmell

■ Long Parameter List
入力 XMLデータの大きさは BPEL の問題ではない

■ FeatureEnvy
オブジェクトの話なので関係ない

■ DataClumps
やり取りするデータの話なので、XMLSchema の問題

■ PrimitiveObsession
これも強いて言えば XMLSchema の問題

■ SwitchStatements
オリジナルはswitch の代わりに多態を使えというものだが、BPELでは関係ない

■ ParallelInheritanceHierarchies
継承の話なので関係なし

■ MessageChains
オリジナルはあるデータにアクセスするためのオブジェクトの経路に、クライアントが全面的に依存してしまっている「デメテルの法則」違反を指しているが、BPEL プロセスで XPath を用いてアクセスするのは問題ない。

■ InappropriateIntimacy
オブジェクト指向でのクラスの凝集性の話で関係ない

■ DataClass
オブジェクト指向でのカプセル化の話なので関係ない
※本質的な意義を持たないという意味では、サービスをinvoke しないプロセスとか

■ RefusedBequest
オブジェクト指向での継承に関する話なので関係ない

2010年4月7日水曜日

XMLSchema/ベストプラクティス

ネット上で閲覧できる XMLSchema のベストプラクティスがいくつかあるが、そのうちの一つ。

XML Schemas: Best Practices

ベストプラクティスのカタログの典型的なものは、個々のプラクティスやパターンを一つのユニットとして、形式を統一して分類し、列挙したようなものが多いが、これはスキーマ設計をする上での判断の分岐点を示してから、採り得る選択肢をメリット・デメリットと共に詳しく解説していく構成になっている。

以下、簡単な紹介。

Default Namespace - targetNamespace or XMLSchema? →原文
デフォルト名前空間(schema 定義の「xmlns=」に指定するやつ)に何を選ぶか。選択肢は以下。
  • targetNamespace に指定した名前空間をデフォルトとする
    <xsd:schema targetNamespace="○○" xmlns="○○" xmlns:xsd="http://www.w3.org/2001/XMLSchema" ~/>
  • "http://www.w3.org/2001/XMLSchema"をデフォルトとする
    <schema targetNamespace="○○" xmlns="http://www.w3.org/2001/XMLSchema" xmlns:△△="○○" ~/>
  • デフォルト名前空間を使わない
    <xsd:schema targetNamespace="○○" xmlns:△△="○○" xmlns:xsd="http://www.w3.org/2001/XMLSchema" ~/>

原文では、どれを選ぶのかについて好みに依存する部分が大きいとされている。個人的には、(3)のパターンでxmlns:tns="○○"として統一するのが、一貫性も可読性もそこそこ維持できると思う。


Hide (Localize) Versus Expose Namespaces →原文
schema 要素の elementFormDefault 属性を"qualified"にするか "unqualified"にするか。

それぞれの長所短所の解説に加えて、qualified 版とunqualified 版の2つのコピーを提供するというプラクティスが紹介されている。(2重管理になる心配をしてしまうが、どうなんだろう。)

Global versus Local →原文
要素や型を、グローバル(<schema>直下に定義)にするかローカルにするか。

以下、三つの選択肢について解説されている。
  • Russian Doll design・・・ローカルに定義
  • Salami Slice design・・・グローバルに要素を定義
  • The Venetian Blind design・・・グローバルに型を定義

Element versus Type
要素として定義するか型として定義するか。迷うくらいなら型として定義する事が推奨されている。

Zero, One, or Many Namespaces →原文
複数のスキーマを定義する際、どのように targetNamespace を指定すればよいか。3つの選択肢について詳説
  • Heterogeneous Namespace Design・・・個別に targetNamespace を与える
  • Homogeneous Namespace Design・・・一個の targetNamespace で統一
  • Chameleon Namespace Design・・・主となるスキーマにtargetNamespaceを与え、従となるものには与えない

Variable Content Containers →原文
複数種の要素を載せるコンテナ要素の定義の仕方。4つのアプローチについて詳説。
  • an abstract element and element substitution
  • a <choice> element
  • an abstract type and type substitution
  • a dangling type

Composition versus Subclassing →原文
オブジェクト指向プログラミングにおける「継承かコンポジションか?」という問題と同じで、やはり Composition が強く推奨されている。

Creating Extensible Content Models →原文
スキーマモデルにどのように拡張性を与えるか。
  • Extensibility via Type Substitution
  • Extensibility via the Element
後者が推奨されているが、Non-Determinism問題への注意が喚起され、<other>要素を用いた回避策の紹介がある。

Extending XML Schemas →原文
ある XML文書をチェックするのに XMLSchemasの文法だけで足りない場合にどうするか。以下3解法の長所短所を解説。
  • Supplement with Another Schema Language
  • Write Code to Express Additional Constraints
  • Express Additional Constraints with an XSLT/XPath Stylesheet

Should the targetNamespace be a URL or a URN? →原文
URL/URNの使い分けについての考察。本来ユニークな識別子にすぎない名前空間の指定に URL が使われると、これがリソースのロケーションと誤解されることが多いという問題が、まず提起される。この問題を踏まえたうえで、将来性としては URL に分があるとし、回避策として http://の代わりに namespace://やxmlns://を用いるというプラクティスが紹介されている。

What's the best way to version schemas? →原文
スキーマの変更にともなうバージョン管理・使い分けの手法
  • Change the (internal) schema version attribute.
  • Create a schemaVersion attribute on the root element.
  • Change the schema's targetNamespace.
  • Change the name/location of the schema.

Achieving Maximum Dynamic Capability in your Schemas →原文
ダイナミックであるほど良い XMLSchema であるという価値観をまず提示。その心得を「postpone decisions as long as possible」として打ち出している。以下の2つのプラクティスが紹介されている。
  • targetNamespace を指定しないままにしておく
  • <import>のschemaLocationを指定しないままにしておく
targetNamespace は常に指定するべしというプラクティス集もあるが・・・

2010年4月5日月曜日

OSS 11g/JMS Adapter

Oracle SOA Suite 11g で JMS Adapter を使ってみる。

非同期で受け取った SOAP メッセージを、メディエータ経由でJMSにキューイングするルーティングを、コンポジットで実装してみたい。

最初は、BPEL から JMS にキューイングするプロセスを考えたけど、要はコンポジットでのJMS アダプタの設定が肝であって、BPELからのJMS 呼び出しは他の <invoke>と変わらず、Getting Started 目的としては BPEL は蛇足だと気づいて割愛。コンポジットだけで構成した。

■■ JMS キュー作成
以下の3つを Weblogic コンソールで設定する
  • キュー作成
  • コネクションファクトリ作成
  • コネクションプール作成

■ JMS キュー作成
  • Domain Structureで base_domain/Services/Messaging/JMS Modules を選択
  • JMS Modulesで SOAJMSModuleを選択
  • [New] 押下→"Queue"を選択 → [Next]
    • Name: greetingQueue
    • JNDI Name: jms/greetingQueue
  • [Next]
    • Subdeployments:SOASubDeployment
    • Targets/JMS Servers:SOAJMSServer
  • [Finish]


■ JMS Connection Factory 作成
  • Domain Structureで base_domain/Services/Messaging/JMS Modules を選択
  • JMS Modulesで SOAJMSModuleを選択
  • [New] 押下→"Connection Factory"選択 → [Next]
    • Name: greetingCF
    • JNDI Name: jms/greetingCF

  • [Next]→ [Finish]


■ Connection Pool 作成
  • Domain Structureで base_domain/Deployments を選択
  • Deployments テーブルでJmsAdapterを選択
  • Settings for JmsAdapter/Configurationタブ/Outbound Connection Poolsタブ
  • [New]
  • oracle.tip.adapter.jms.IJmsConnectionFactoryを選択して[Next]
    • JNDI Name: eis/Queue/greeting
  • [Finish]※deployment plan location とか言うのを聞かれたら適当にディレクトリを掘って、パスを指定する
  • Configurationタブ/Outbound Connection Poolsタブに戻る
  • oracle.tip.adapter.jms.IJmsConnectionFactory を展開して、eis/Queue/greetingを選択
  • ConnectionFactoryLocation の Property Value に jms/greetingCF を指定
  • [Save]
  • Deployments テーブルに戻って JmsAdapter を再デプロイ(チェックして[Update])


■■ コンポジット・アプリ作成
■プロジェクト作成
  • 名前:ここでは SimpleJmsQueueing とした
  • プロジェクトテクノロジ:SOA
  • コンポジットテンプレート:空のテンプレート

このコンポジットで使う XML スキーマを、以下のように作成。
  • SOAコンテンツ/xsd フォルダのコンテキストメニューから[新規]
  • ファイルを選択し、message.xsdを作成。内容は以下。
    <schema xmlns="http://www.w3.org/2001/XMLSchema"
    targetNamespace="http://studies.oss11g/simple.jms.queueing"
    xmlns:tns="http://studies.oss11g/simple.jms.queueing"
    attributeFormDefault="qualified" elementFormDefault="qualified">
    <element name="greeting" type="tns:GreetingType"/>
    <complexType name="GreetingType">
    <sequence>
    <element name="message" type="string" />
    </sequence>
    </complexType>
    </schema>


■ Webサービス
  • Webサービスを[公開されたサービス]のレーンにドロップ
  • 歯車ボタンでスキーマから WSDL を生成
  • リクエストタブでURLに message.xsd の greeting 要素を選択
    レスポンス以下のタブは放置
  • 他はめんどくさいので全部デフォルト


■ JMS アダプタ
  • [外部参照]のレーンにJMS アダプタをドロップ
  • 名前はここではJMS_Queueとした。
  • JMSプロバイダに Oracle Weblogic JMS を指定
  • AppServer 接続:デプロイとかで使ってるいつものやつ
  • アダプタ・インタフェイス:操作およびスキーマから定義
  • 操作:メッセージ発行、操作名はデフォルトまま
  • 発行操作のパラメータ:
    • 接続先名:参照ボタンで greetingQueue を指定
    • JNDI名:eis/Queue/greeting
  • メッセージ
    • URL:message.xsd の greeting を指定
  • 終了


■ メディエータ
  • [コンポーネント]レーンにメディエータをドロップ
  • 名前:デフォルト/テンプレート:デフォルトのまま
  • Mediator1 から Service1 と JMS_Queue にワイアリング
  • Mediator1 の編集開始
    • 「次を利用して変換」の×ボタンを押下
    • 「新規マッパーファイルの作成」を選択して[OK]
  • 開いた XSLT エディタで左の message と右の message をつなげる

■■ テスト
SoapUI か EMコンソールから、いつもどおりにリクエスト送信。キューに入ったメッセージは WebLogic コンソールから確認できる。

2010年4月4日日曜日

SOA Composer

Oracle SOA Suite 11g の Release 1 Patch Set 1 (11.1.1.2.0)から、デプロイした後にWebブラウザからビジネスルールを編集するための、SOA Composer というものが使えるようになった。

http://{server}:{port}/soa/composer でアクセスできる。

前々ポストのIF-THENルールの編集画面

前ポストのデシジョンテーブルの編集画面

2010年4月3日土曜日

OSS 11g/Business Rule 2

前ポストで IF-THEN を使った BusinessRule を試してみた。今度は Decision Table でやってみる。

■ 仕様
前回とほぼ同じで、入力文字列が5文字以上なら文字列"LONG"、でなければ文字列"SHORT"を返すという仕様。これを Webサービス → BPELプロセス → ビジネスルールの構成で動かしてみる。アホらしい仕様だが、Getting Started なのでこんな感じ。

■ 環境
・Oracle SOA Suite 11g (11.1.1.2.0)
・Oracle JDeveloper 11g

■ コンポジット作成
  • プロジェクト名:適当。ここではSimpleDecisionTable とした
  • プロジェクト・テクノロジ:SOAを選択
  • コンポジット・テンプレート:BPEL を使用するコンポジット
※勝手にBPELプロセスの作成が始まる。以下の作業に続く。

■ BPELプロセス作成
  • 名前:適当。ここでは SimpleDecisionTableProcess とした
  • テンプレート:同期BPELプロセス
  • SOAPサービスとして公開:チェック

■ スキーマにファクトを追加
SimpleDecisionTableProcess.xsd が自動生成され、process と processResponse の定義が含まれているが、これを更に以下のように編集
  • 列挙型 CategoryValueを追加
    <simpleType name="CategoryValue">
    <restriction base="string">
    <enumeration value="SHORT"/>
    <enumeration value="LONG"/>
    </restriction>
    </simpleType>
  • BusinessRuleに与えるファクトを追加
    <element name="facts">
    <complexType>
    <sequence>
    <element name="length" type="int"/>
    </sequence>
    </complexType>
    </element>
  • 既存のprocessResponse/resultの型を CategoryValue に変更(名前空間のプレフィクスも適当は調整しておく。)

■ BusinessRule 作成
  • composite.xml を開く
  • コンポーネントのレーンにビジネスルールをドラッグ
  • 適当に名前を指定。ここでは LenghtCategoryTable とした。
  • 緑のプラスボタンで入力を追加
    • プロジェクトのスキーマ・ファイルからfacts を選択
  • 緑のプラスボタンで出力を追加
    • プロジェクトのスキーマ・ファイルからprocessResponse を選択
  • 作成したビジネスルールにBPELプロセスからワイアリング
※ルールの定義は後で。

■ BPEL の編集
  • receiveInput と replyOutput の間に Assign を置いて、以下のようなコピー操作を追加
    • From:string-length(bpws:getVariableData('inputVariable','payload','/client:process/client:input'))
    • To:/変数/プロセス/変数/facts/client:facts/client:length

  • 上で追加した Assign の下にBusinessRule を置く
    • 名前は適当。ここでは デフォルトのままとした。
    • ディクショナリに LenghtCategoryTable を指定
    • 以下のように入力ファクトを追加
      • From:変数/プロセス/変数/facts/client:facts
      • To:変数/{凄い長い名前の変数}/client:facts
        ※To の「変数」は、ダブルクリックしないと展開されないので注意。展開すると凄い長い名前の変数が表示される
    • 以下のように出力ファクトを追加
      • From:変数/{凄い長い名前の変数}/processResponse
      • To:変数/プロセス/変数/outputVariable/payload/processResponse

■ デシジョン表の作成
  • composite.xmlからビジネスルールの編集を開始
  • 緑のプラスボタンから[デシジョン表の作成]
    • バケットセットの編集
      • 範囲リストの追加
      • 名前:LengthRange/データ型:int/フォーム:Range
      • さらに以下のように編集
    • ファクトの編集
      • facts を選択して編集開始
      • lengthのバケットセットに LengthRange を設定
    • ルールセット Ruleset_1 を選択して編集
      • こんな感じにする

■ デプロイ-テスト
  • SimpleBusinessRule のコンテキストメニューからデプロイ
  • SoapUI か emコンソール からリクエストを送る
    • process/input に空文字列, "abcd", "こんちは"等を指定すると"SHORT"
    • process/input に"abcde", "こんにちは"を送ると"LONG"が返ってくる

■ 雑感
今回やったようなのは極端に簡単な処理なので、標準BPEL コードでも出来ることではあるけど、BPEL から Business Rule として切り出すことで、一般的に以下のような効用が期待できる。

(1) BPEL プロセスの簡素化
BPEL の本来の目的からも、またスパゲティ化を回避する意味でも、他サービスをオーケストレイトしない制御ロジック(繰り返し/条件分岐)は BPEL に含めるべきではない。その変わりに XSLT か BusinessRule として切り出して BPEL をシンプルに保つべき。(設計上の都合に由来するなら XSLT、ビジネス要因に由来するものは BusinessRule。)

(2) ビジネスルールの外部化
コンポジットアプリをデプロイした後からでも、ビジネスの変更を契機として
ルールだけを独立に変更したい状況もある。またこの作業を、いちいち IT層 の人間に頼まずに、ビジネス層の人間が直接実施するニーズもあるはず。そうなると BPEL や XSLT では敷居が高いが、Business Ruleにしておけば、ウェブベースのルールエディタを使ってデプロイ後にも編集できる(11.1.1.2.0)。

2010年4月2日金曜日

OSS 11g/Business Rule 1

シンプルな BusinessRule を作ってみる。

IF-THEN と デシジョンテーブルがあるが、今回は IF-THEN でやる事にした。

■ 仕様
BPEL プロセスからビジネスルールを実行するという事にだけ着目したいので、いつものごとく、極力シンプルな仕様にする。
  • SOAP で公開された BPEL プロセスが、リクエストメッセージ中の XMLデータをビジネスルールに渡す。
  • ビジネスルールは受け取った XMLデータ中の <input>要素の文字列長を判別して、5文字以下なら文字列"SHORT"、5文字長なら文字列"LONG"を<result>要素に設定したレスポンスメッセージを生成する。
  • BPEL プロセスは、ビジネスルールが生成したレスポンスをクライアントに返す

■ 環境
・Oracle SOA Suite 11g (11.1.1.2.0)
・Oracle JDeveloper 11g

■ コンポジット作成
  • プロジェクト名:任意。ここではSimpleBusinessRuleとした
  • プロジェクト・テクノロジ:SOAを選択
  • コンポジット・テンプレート:BPEL を使用するコンポジット
※勝手にBPELプロセスの作成が始まる。以下の作業に続く。

■ BPELプロセス作成
  • 名前:適当。ここでは SimpleBusinessRuleProcess とした
  • テンプレート:同期BPELプロセス
  • SOAPサービスとして公開:チェック

■ BusinessRule 作成
  • composite.xml を開く
  • コンポーネントのレーンにビジネスルールをドラッグ
  • 適当に名前を指定。ここでは LengthCategory とした。
  • 緑のプラスボタンで入力を追加
    • プロジェクトのスキーマ・ファイルからprocess を選択
  • 緑のプラスボタンで出力を追加
    • プロジェクトのスキーマ・ファイルからprocessResponse を選択
  • 作成したビジネスルールにBPELプロセスからワイアリング
※ルールの定義は後で。

■ BPEL の編集
  • receiveInput と replyOutput の間に Business Rule を置く
  • 名前は適当。ここでは CategorizeLength とした。
  • ディクショナリに LengthCategory を指定
  • 以下のように入力ファクトを追加
    • From:変数/プロセス/変数/inputVariable/payload/process
    • To:変数/{凄い長い名前の変数}/process
      ※To の「変数」は、ダブルクリックしないと展開されないので注意。展開すると凄い長い名前の変数が表示される
  • 以下のように出力ファクトを追加
    • From:変数/{凄い長い名前の変数}/processResponse
    • To:変数/プロセス/変数/outputVariable/payload/processResponse

■ ルールの作成
  • composite.xmlからビジネスルールの編集を開始
  • 緑のプラスボタンから[ルールの作成]
    • テストの挿入: process.input.length() <= 5
    • アクションの挿入: assert new processResponse(result:"SHORT")
  • 緑のプラスボタンからもう一個[ルールの作成]
    • テストの挿入: process.input.length() > 5
    • アクションの挿入: assert new processResponse(result:"LONG")
下図のようになる
※「<何とかの挿入>」というリンクをクリックして内容を組み立てていく方式だが、ちょっとクセがある。説明するのはちょっと難しいけど、やってみると使い方はすぐ分かる。

ただし難しくて理解しにくい事は無いけど、別に使い易い事もなく、むしろ、なんか面倒くさい。言語リファレンスとAPIドキュメントさえ見やすいところに用意してくれてさえいれば、こんな感じのバカチョン的なフォームよりも、自動補完付きのソースエディタの方がマシな気がする。

JDeveloper - SOA Composite Editor 全般でそんな印象を受ける。ルールエディタだけなら、ビジネスピープルを意識してこうなったのかとも思うけど、他はどうなんだろう。


■ デプロイ-テスト
  • SimpleBusinessRule のコンテキストメニューからデプロイ
  • SoapUI か Enterprise Manager からリクエストを送る(SoapUI の方がお勧め)
    • process/input に空文字列,"a", "abcde", "こんにちは"等を指定すると"SHORT"
    • process/input に"abcdef", "こんにちは!"を送ると"LONG"が返ってくる


■ 次回予定
デシジョンテーブルで同じようなことをやってみる。あと BPEL プロセスとビジネスルールの関係についてちょっと考えてみたい。

2010年3月31日水曜日

BPEL 要員の集め方

前のポストで BPEL スキルについてあれこれ考えて、こんな図を描いてみた。
これをベースに要員調達について、特にどんなスキル・キーワードを条件として用いるべきか考えてみる。ポイントは以下のようになる。
  • 上図、また前ポストで示したように、BPEL技術は階層を成したXML技術構造のやや上層に位置し、XML×SOA×ワークフローが交叉する複合的な技術でもある。この特性をどう扱うか。
  • そもそもBPEL 技術者は絶対数が少ないが、これにどう対処するか。

■ 駄目な集め方
多分、こんな感じだと上手くいかない。
必須スキル:○○社BPEL製品

調達担当者は、「○○社BPEL製品経験者」ならば、当該製品のノウハウはもちろん BPEL標準仕様からXML・SOAの基盤技術まで一通りマスターしているだろうと考えて、下図のようなスキル分布を期待する。(調達担当者が要素技術について多少なりと理解しているという想定。やや楽観的だが。)
ところが現実の応募してくる人のスキル分布は、こんなふうになる。

畢竟、ただただ言われるままに、IDE上のグラフィカルなエディタを何十時間かいじってきただけの経験だと、どこまでが現場のローカルルールで、どこからがツールの仕様で、どの辺りが標準仕様なのか全く未分化なままだし、それを自覚することもないから、応用というものが全くきかない。XMLソースを普通に読み書きするだけの事を、異様に恐れたりするレベルの人。

で、普通なら正味のスキルを面談時に精査して、合格レベルに満たないなら次の応募者に期待という事になるが、そもそも BPEL技術者の絶対数が少ない上に、さらに「△△社」で絞っているものだから、「選ぶ」なんて贅沢な余裕が生じる程、応募者は来てくれない。

こんな応募条件を出すくらいだから調達者側のレベルからして推して知るべしで、面談で正しくスキルチェックができるほどの技量もない。従って、結局は職務経歴書に記載の「△△社BPEL製品」という記号の有無だけで採用が決まり、面談は形式的な挨拶程度ということになりがち。


■ マシな集め方
改善するとこうなる
必須のスキル
 ・XMLスキル(XSLT、XPath、XML Schema)
 ・SOA、Webサービス
望ましいスキル
 ・BPEL (○○社製品ならば尚可)
 ・その他ワークフロー技術
とりあえず、応募者がいないと比較も選別もできないから、思い切って該当者の少ない BPEL経験は必須から外してしまう。それに替えて XML/Webサービスのスキルを必須とし、高スキル技術者を募る。XML/Webサービス技術者も中~高レベルのとなるとそう多くはないが、それでも同等レベルの BPEL技術者よりは、はるかに流通している。

下図のような技術者を期待して待ち、首尾良けば、複数の候補者からベストな数名を採用してチームに組み入れる事になる。
もちろん BPEL 標準および△△社のツール/プラットフォームについての学習工数が発生する事にはなるが、基礎スキルが充実していれば採用者側が心配するほどには時間も労力も掛からない。

また上述の駄目な例として挙げたような特定ベンダーの条件を外すことで、下図のような技術者にも門戸を開くことになる。

このタイプの BPEL 技術者なら、作業開始の要点とローカルルールについて簡単にレクチャーし、座席を適切に配置しておけば、業務要件の把握していく作業のついでに自然と習得できてしまう。
むしろ、XML 良く知ってる人が BPEL や 特定ツールを習得するための工数について、募集側が過度に多く見積もっている場合、プロセスを BPEL で書くという作業を募集側自身が良く理解していない可能性がある。

つまるところ「XMLで定義・公開され、XMLをやり取りするサービスを、XMLで記述したプロセスで動かす。」という事に尽きるわけで、必要なスキルがどんなものなのか簡単に分かりそうなものだが、実際の現場はそうじゃなかったりする。


■ 応募者側からの見方
ここまで募集する側の視点で書いたけど、逆に応募する側、BPEL技術者の視点から言うと、「BPEL経験」だとか「○○社BPEL製品」なんて必須指定がある案件は、募集側の見識を疑ってかかる事もできる。

特に、そういった選択肢を過度に狭め得る条件を必須にしておきながら、そのくせ「急募」だったり「稼働時間高」なんて場合は、プロジェクト自体も採用側の思考も、とっくに破綻していると考えてまず間違いない。

まあ不景気だし、金に困っている場合などは、タコ部屋かマグロ漁船に飛び込む気持ちで、敢えて短期間やってみるって選択もありかもしらんが。

2010年3月30日火曜日

OSS 11g/Human Task

シンプルな Human Task を作って動かしてみる。

■■■ 環境/前提/準備
■ 環境
  • Oracle SOA Suite 11g
  • Oracle JDeveloper 11g
  • サーバ: 192.168.0.3(余りに重いので作業マシンとサーバマシンを分けた)
  • Weblogicコンソール: http://192.168.0.3:7001/console/
  • Enterprise Manager: http://192.168.0.3:7001/em/
  • ワークリスト: http://192.168.0.3:7001/integration/worklistapp/

■ ユーザ追加
  • Weblogic のコンソールで以下のようにナビゲート
    base_domain > Summary of Security Realms > myrealm > Users and Groupsタブ > Usersタブ
  • New でユーザを追加。 ここでは approver とした。


■■■ アプリ作成
■ コンポジット作成
  • 新規プロジェクト 作成する
    • 名前: 任意(SimpleHumanTaskとした)
    • プロジェクト・テクノロジ: SOAを選択
    • コンポジット・テンプレート: BPEL を使用するコンポジット
※ 勝手にBPELプロセス作成ウィザードが始まる

■ BPELプロセス作成
  • 名前:任意(SimpleHumanTaskProcess とした)
  • テンプレート:非同期BPELプロセス
  • SOAPサービスとして公開:チェック

■ HumanTask 作成
  • composite.xml を開く
  • コンポーネントのレーンにヒューマン・タスクを置く
  • 任意の名前を入力(ここではEvaluation とした)
  • ダブルクリックして編集開始
    • 一般/タイトル:<%'Evaluate Input'%>
    • データ/ペイロードの追加
      • [その他のペイロードの追加]
      • "要素"を選択
      • 虫眼鏡のアイコンからタイプチューザを起動し、以下を選択
        "プロジェクトのスキーマ・ファイル">SimpleHumanTaskProcess.xsd>process
      • ワークリストにより編集可能: チェック
    • 割当てを選択
    • Stage1をダブルクリック
      • タイプ: 単一
      • 値ベース: チェック
      • ユーザの追加
      •  識別タイプ: ユーザ
      •  データ型: 名前別
      •  値: approver (以下のようにアイデンティティ・ルックアップが使える)

  • composite エディタ上で、BPELプロセスから HumanTask にワイアリング

■ BPEL の編集
  • receiveInput と callbackClient の間に HumanTask を置く
  • タスク定義で上で Evaluation を選択
  • タスクパラメータに inputVariable/payload/processを指定
  • taskSwitch を展開して、各case 内のassign を編集
    • REJECTケース内のassign を展開してコピー操作を追加
      • from: 式'rejected'
      • to: output/payload/processResponse/result
    • 同様に APPROVEケースで式'approved', 残りのケースに式'expired'を追加

■ フォームの作成
  • BPELエディタ上でHumanTask を右クリック
  • [タスクフォームの自動生成]を実行
  • しばらく待つとかなりの量のソースが自動生成され、フォームエディタが開いて自動生成完了

■■■ デプロイとテスト
■ デプロイ
  • SimpleHumanTask プロジェクトをデプロイする
  • アプリケーションメニューのデプロイから EvaluationForm をデプロイ
    ※プロジェクトのコンテキストメニューのデプロイではない
    ※万一でぷろいエラー[Deployer:149140]が出たら、Weblogic のコンソールを開いて左上の"Change Center"からセッションをクリア

■ テスト
  • Enterprise Manager で SimpleHumanTask を選択し、[Test]を実行する
  • Input Arguments の領域で、payload/input に 何か適当に入力
  • [Test Web Service] ボタンを押下
    • [Launch Message Flow Trace]を押下するとフローの状態が表示され、BPEL プロセスと Evaluation ヒューマン・タスクが Running 状態のままになのが分かる。
  • ワークリストに ブラウザからapprover でログインすると、回ってきたタスクが表示されている。
  • ダブルクリックするとフォームが開く
  • [承認]ボタンを押す。
    • 再度、Enterprise Manager からプロセスの様子を見ると、全部 Completed になったのが分かる

2010年3月21日日曜日

BPEL スキルの考察

思うところがあって、BPEL スキルがどんな風に構成されているか整理してみた。


術語の定義によっては若干変わるだろうけど(自分でも明日書いたら違うものになると思う)、だいたい上図のように ①XML基礎技術、②サービス指向技術、③ワークフロー技術という3つの技術が交わる領域の、さらに一部分をBPEL が占めるような配置になるんじゃないだろうか。

で、BPEL にはそれ自体に関するスキル以前に前提となるような技術要素あり、それぞれ①~③の領域に含まれていて、上図では特に依存性が強いものについて水色のハイライトで示した。

図中、重なった部分での①~③の各領域は均等の重みではなくて、私見では以下のようなバランスになる。
  • XML 基礎技術 → 5
  • サービス指向技術 → 3
  • ワークフロー技術 → 2
また、それに加えて依存関係の順序もあって、まず XML技術、次にその上にサービス指向技術が重なってXML Webサービス技術の領域を形成し、またその上にワークフロー技術が重なり BPELを含むワークフロー記述用 XML 仕様が来るのだと思う。

さらに、実際のプロジェクトでは標準仕様を独自に拡張した何らかの製品を使うので、この一層も含めて、今度は縦に切った形で図式化すると以下のようになる。
以上のようなイメージが、BPEL スキルの内訳とその依存関係、また BPEL 周りの周辺技術について自然に思い浮かぶものだと思う。まあ主観に違いないけれど、XML、SOA、ワークフローを体系的に勉強した経験があれば、細部を除いて概ね意見が一致する自明な認識ではなかろうか。

ところが、現実のプロジェクトで各種の残念な事情が重なると、これと全く違うイメージが形成されて、マネージメント層から業務エンジニア層・プログラマ層までプロジェクトチーム全体で共有されてしまう事がある(あるいは共有されているかのように振舞うことを強いられる)。

まだ上手くまとまらないが、列挙するとこんな感じ。
  • プロジェクトで採用された特定ベンダの BPEL 実装を、BPELの全てだと思い込んでいる。
  • 最初に示した図と内外を逆に、「BPEL」という大きなカテゴリに XSLTなどの基礎 XML 技術や、SOA や WSDL などの Webサービス技術が包含されていると思い込んでいる。
  • 特定ベンダの BPEL ツール使用経験を見て、XML基礎技術、サービス指向技術、ワークフロー技術のスキルレベルまでも満たされているものと思い込んでしまう。
脳内イメージは、たぶんこんな図式と推測できる。
このように、スキル要素の捉え方が大幅に間違っていると、プロジェクトの運営に当たって至る所で(教育、人員調達、情報共有、etc.)問題が生じる事は、リーダ/マネージャ経験者ならすぐ想像がつくと思う。

後日、今回の記事をベースにもうちょっと敷衍してみたい。