最近、あるソフトハウスの新人が、準委任契約の開発現場にアサインされるにあたって、顧客企業の開発部門の責任者の面接を受ける事になり、その現場に居合わせる機会を得た。
で、本人のスキル不足に関しては、新人だからと言う事で、まあしょうがないという雰囲気だったが、xUnit の経験が無いという話になると、顧客側責任者から、その新人に同行したソフトハウスの上司に対して厳しい指摘が飛んだ。
曰く、「これからの現場では、xUnit を用いたテストコードによる自動テストを"しなくてよい"なんて事はあるわけが無いから、新人研修では絶対にテスト駆動開発も教えるべき。」という事だった。
私としては、立場上、浮かれた態度を取れない状況だったので、その場ではほぼノーリアクションで神妙にしてたけど、内心は「我が意を得たり」の心境で、ちょっと気分が良かった。
開発の現場にいると、「先にやっておくべきことを後に回すと、利子がついて何十倍にもなって跳ね返ってくる」という事が実によくあるが、この最高の典型例がユニットテストだと思う。
テスト・ファーストとテスタビリティの関係は、「テストを先に書くから、低テスタビリティ・コードが書きにくい」という面と、「低テスタビリティ・コードが書かれる前だから、テストも先に書きやすい」という面が、互いにループ状に補完しあうようになっている。
このシンプルで美しい因果関係がわからない人が、未だに多い。先に書けない人間が後で書けるわけが無いのに、後の方が書きやすそうなんて勘違いして、結局挫折して、テスタビリティもカバレッジも最低のコードを垂れ流してくる。
という訳で、「後付テストの方がテストファーストより簡単」なんて考えてる迂闊なPGをこれ以上増やさないためにも、新人の研修プログラムもテストファーストで組み立ててみてはどうかと思う。
前述の面接での助言だと、単に新人研修にテストファーストを組み入れましょうという話だが、それだけだと手ぬるい。そんな事だと、テストコーディングはカリキュラムの最後の方にまわされて、終いには「後は各自勉強する事」なんて感じで省略されるのがオチ。
だから、まず最初にテスト。プロの現場の教育は「テストありき」で教える。高カバレッジ・高テスタビリティを最初から維持したまま、プログラムが成長していく様を骨の髄まで体得させる。
つうか、まあ、指導者のスキルも物凄く問われてしまうが。
2010年7月29日木曜日
2010年7月26日月曜日
Test Smells - Slow Tests
TestComplete というテストツールを使って UI操作を自動実行するスクリプトの記述作業に、途中参加することになった。
話を聞くと、既に完成した部分では、テスト実行時間がハチャメチャに長いスクリプトになっているらしい。一つのフォームについて、合計して小一時間のテスト群があって、それが数十フォームあるから全ケースで軽く一日は超える事になる。これは、かなりのレベルの Slow Testsだと思う。
つうか、Slow Tests も困った事だが、それ以上に脱力するのが、その弊害を誰もまじめに考えて来なかったと言う点だったりする。
しかも、今までこの自動化テストを指揮してきたリーダが、同時に Coutinuous Integration に関連するチームのメンバでもあったりして、そんな人が Slow Tests という Test Smell の中でも最たるものを等閑視してきたわけだから、何かビックリしてしまう。
今まで、常時結合とかについて議論してきたのはなんだったんだろうと、こっちがしょんぼりしてしまう。Daily も無理じゃん・・・
とりあえず気を取り直して、以下、教科書どおりの処方
しかし、こういう風に後から入って行って何かを是正しようとすると、たいてい前任者の心理的抵抗に会ったりしてちょっと面倒くさい(本当はシステム開発を面白がるブログのはずなんだが、最近は愚痴の方が・・・)
話を聞くと、既に完成した部分では、テスト実行時間がハチャメチャに長いスクリプトになっているらしい。一つのフォームについて、合計して小一時間のテスト群があって、それが数十フォームあるから全ケースで軽く一日は超える事になる。これは、かなりのレベルの Slow Testsだと思う。
つうか、Slow Tests も困った事だが、それ以上に脱力するのが、その弊害を誰もまじめに考えて来なかったと言う点だったりする。
しかも、今までこの自動化テストを指揮してきたリーダが、同時に Coutinuous Integration に関連するチームのメンバでもあったりして、そんな人が Slow Tests という Test Smell の中でも最たるものを等閑視してきたわけだから、何かビックリしてしまう。
今まで、常時結合とかについて議論してきたのはなんだったんだろうと、こっちがしょんぼりしてしまう。Daily も無理じゃん・・・
とりあえず気を取り直して、以下、教科書どおりの処方
- 第一候補:Fake Object パターンを使って、遅い部分を置き換える。
- 第二候補:Shared Fixture パターンを使ってセットアップコストを抑える(但し、Erratic Test アンチパターンを避けるため、immutable(不変)にすること)。
しかし、こういう風に後から入って行って何かを是正しようとすると、たいてい前任者の心理的抵抗に会ったりしてちょっと面倒くさい(本当はシステム開発を面白がるブログのはずなんだが、最近は愚痴の方が・・・)
2010年7月19日月曜日
Software factory → 技術者の棲み分け
自動車工場の生産ラインを超おおざっぱに言うと、だいたいジャングルジムくらいの機械をベルトコンベアで何台かつなげたもので、いろんな小っさい部品(輪っかとか、丸っこいのとか、筒みたいなのとか)を組み合わせて、より上位の足回りやブレーキといった部品を作るような、一連の流れ作業を担っている。
ラインに組み込まれる個々の機械は、部品と部品を組付けたり、溶接したり、塗装したり、油を注入したりするもので、あるものは全自動、別のものは半自動だけど、人手が介入する部分は単純化されていて、工学的素養や、職人的技能が要求される事はほとんどない。出稼ぎ労働者や期間工が、担当したりする。
工場では、新車種対応だとか、増産だとかいったきっかけで、生産ラインを組み替えたりするので、そこに組み込む機械を、自社の部門だとか外部の「ナントカ精機」みたいな機械製造会社にオーダーメイドで発注する。で、普通は、設計、電気、組み付けのそれぞれの職人がアサインされて、協力して機械を製作する(旋盤やフライスを使って、鉄の塊から部品を切り出す加工屋さんも関わってくる)。
この職人さん達は、それぞれの担当分野のプロフェッショナルなわけだけど、それぞれの腕前が品質や生産性に反映するから、やり甲斐があって面白いし、だからよく勉強もする。それに基本的に世の中に一台から数台しかない機械なので、なんとなく愛着のようなものも持っていたりもする。
当たり前の事だけど、生産設備を作る機械職人と、その設備を使って部品を組み立てるライン作業者との間には、基本的には棲み分けがある。メーカの社員が両方をこなす事も、あるにはあるだろうが、基本的には前述のとおり、機械職人は機械屋さんだし、ライン作業者は出稼ぎの期間工だったりする。仕事の成果物も違うが、それ以前に、持っている職能も、もの造りへのスタンスも背景も、全く異なっている。
前置きが長くなったが、このところ聞かなくなったソフトウェア・ファクトリについて、上述のような、「技術者の棲み分け」を促進するのではないかと、ちょっと期待していた。つまり、ファクトリという生産設備を作る高スキル・グループと、それを使って製品を作る低スキル・グループに、いっその事、従来以上にスッパリ分離してしまってはどうかという疑問に、答えを提供してくれるのではと。
従来、SI屋が技術者の棲み分けを施す場合、フレームワーク/ライブラリに関連するチームに比較的高スキルの要員を割り当てて、それを用いるビジネスロジックを担当するチームに低スキルの要員を割り当てる事が多かった。
でも、この役割分担だと、つまるところ同じ平面上で共通部分と固有部分に要員を振り分けているにすぎず、結局は同じ言語、同じ規約、同じ最終成果物に対しての作業になるわけだから、いたるところでギャップが生じて、互いの不経済を引き起こす。
すなわち、低スキル技術者は、高スキル技術者達の間ではごく当たり前な慣用句に過ぎない、ありふれたデザイン・パターンやイディオムがチンプンカンプンだったりするし、一方、高スキル技術者の方でも、三項演算子すら分からない低スキル技術者が迷子にならないように、自己の能力も言語/APIのポテンシャルも大幅に抑制する事になる。
例えば、良かれと思って、「流れるようなインターフェイス(fluent interface)」のスタイルでAPIを書いたとしても、使う側が最底辺技術者のグループだと、「いつもと違う。見たことが無い。」なんて感じで、総スカンを食らう可能性がある。
こういった無駄な軋轢を避けるためにも、高スキル技術者をメタレベルの作業領域、つまり生産設備=ファクトリの開発作業に従事させて、低スキル技術者とは干渉しようもないレベルに分けてしまうのが良案なのではないかと。(もちろんギャラも、容赦なく差をつけるべきだが。)
低スキルな技術者達というのは、プログラム言語や APIについて勉強する事が、本当に何よりも嫌いでたまらない人達なわけだから、そんな理不尽な苦痛は、人道的観点からもなんとかして少なくしてあげたい。そのために、覚える事がいっぱいな従来通りの汎用言語に替わる簡易な言語として、DSL を与えてあげるのが良いのではないか。
この DSL を定義する 高スキル技術者グループの方でも、リテラシの貧弱な読者を気にする事無く、スキルを最大限に発揮して、言語/API の本来の力を最大限に引き出して、最高のコードを書くことができる。最も簡易で優しいドメイン特化言語を、最も高度な技術で、のびのびと開発すればいい。
と、まあ、理想はこうだけど、何をどう分離して、どこまでファクトリ化するか具体的に考えたら、やはりなかなか難しい。正にそれをソフトウェアファクトリが提示していたんだろうけど、普及する前に消えてしまったようだし、やはり何か無理があったのか。
ラインに組み込まれる個々の機械は、部品と部品を組付けたり、溶接したり、塗装したり、油を注入したりするもので、あるものは全自動、別のものは半自動だけど、人手が介入する部分は単純化されていて、工学的素養や、職人的技能が要求される事はほとんどない。出稼ぎ労働者や期間工が、担当したりする。
工場では、新車種対応だとか、増産だとかいったきっかけで、生産ラインを組み替えたりするので、そこに組み込む機械を、自社の部門だとか外部の「ナントカ精機」みたいな機械製造会社にオーダーメイドで発注する。で、普通は、設計、電気、組み付けのそれぞれの職人がアサインされて、協力して機械を製作する(旋盤やフライスを使って、鉄の塊から部品を切り出す加工屋さんも関わってくる)。
この職人さん達は、それぞれの担当分野のプロフェッショナルなわけだけど、それぞれの腕前が品質や生産性に反映するから、やり甲斐があって面白いし、だからよく勉強もする。それに基本的に世の中に一台から数台しかない機械なので、なんとなく愛着のようなものも持っていたりもする。
当たり前の事だけど、生産設備を作る機械職人と、その設備を使って部品を組み立てるライン作業者との間には、基本的には棲み分けがある。メーカの社員が両方をこなす事も、あるにはあるだろうが、基本的には前述のとおり、機械職人は機械屋さんだし、ライン作業者は出稼ぎの期間工だったりする。仕事の成果物も違うが、それ以前に、持っている職能も、もの造りへのスタンスも背景も、全く異なっている。
前置きが長くなったが、このところ聞かなくなったソフトウェア・ファクトリについて、上述のような、「技術者の棲み分け」を促進するのではないかと、ちょっと期待していた。つまり、ファクトリという生産設備を作る高スキル・グループと、それを使って製品を作る低スキル・グループに、いっその事、従来以上にスッパリ分離してしまってはどうかという疑問に、答えを提供してくれるのではと。
従来、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
システムに価値をもたらさなかったり、既にアクティブ・リストにないユースケースは取り除いてしまう事。
■■■ 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 上巻』の変数の部に詳述されているので、理屈を確認したければこの辺りを読めばいい)
★ 一時変数が少なくて済む
三項演算子はもちろん演算子だから、式を書ける所ならば普通に使えるので、わざわざ作業用の一時変数を使わないで済む場合がある。
※一時変数の使用と不使用とでどちらが望ましいかなんて解説は省略。
※『リファクタリング』に「説明用変数の導入」という一時変数を増やす事になる小技が載っているが、それとは別の話
★ 重複コードを解消できる
上の どちらのFoo()も、条件分岐/条件演算を 別のメソッド Baz() に移して値をすぐに return させるようにすると、共にBar(Baz(f))という形に置き換えることができるが、それでも、まだ微妙な重複が残る。
★ 不要なブロックを減らせる
ブロックが多い(深い)のと少ない(浅い)のでは、少ない方に決まっているという普通の話。(自明のように見えるが、実はプログラマの中にはブロックをどんどん深くして悦に入る人もたまにいる。これ以上くどい説明もアレなので省略するが・・・)
コードブロックに関して突き詰めていくと、ブロックそのものが、長過ぎるメソッド/一時変数の濫用/重複コード/スパゲティコード/オブジェクト指向を無視した手続き型ロジックやらの温床でもあり元凶でもあるように見えてくる。他のトレードオフも考慮した上で、できるだけ式かメソッド呼び出しに変えてしまった方が、将来的にも安全なコードになる。
三項演算子を「使うべき」理由は、こんなところか・・・
続いて、よくある三項演算子反対の意見に反論してみる。
== == == == == ==
■ 三項演算子否定論への異議
★三項演算子は難しいから禁止すべき。
そもそも「難しいか否か」なんて主観的判断が、合理的評価基準として妥当なのか疑問だが、差し当たりこれを認めるとして、それならば他の言語要素に関しても三項演算子より難しいものは否定してしまうのかという話になる。LINQ はどうか?ラムダ式はどうか?ジェネリクスは簡単か?
何かの言語要素を難しいと感じた誰かさんが(難しさを認識する事自体は望ましい事だが)、それを一律に禁じてしまうような事で、言語という道具と、それを操るプロフェッショナルから、投下したコストに対する効用を最大限に引き出す事が本当に可能なのか疑わしい。ちゃんと分かって、禁止しているのだろうか?むしろ、その禁則さえなければ得られたはずの利益を捨ててしまっていないか?
また「平均的プログラマの技術水準」なんて怪しい設定を持ち出して、三項演算子は無理なんて主張する人も多いが、どこに根拠あるんだろう?というか、
「三項演算子ができないレベルで妥協した方が、人材調達が容易」なんて言い分もあるようだが、それって「我々のスタイルは、基礎的な文法要素も使えない、最底辺PGによる人海戦術です」なんて言うのと同義なわけだけど、マジでそんなので良いのかな。三項演算子どころではない大問題だと思うんだが・・・
★ 三項演算子は読みにくいから禁止
三項演算子の方が読みやすいと言う人もいるし、どっちでも変わらないという人もいて、結局、単なる主観なわけで、フォーマルな規約の根拠としては元々ふさわしくない。
あと、読みにくさの話になると、ことさら読みにくくした三項演算子コードのサンプルだけを引き合いに出して「ほら、こんなに読みづらい」なんて言う人が必ず出て来るけど、そういうのはスルー。
★ 三項演算子はミスを生じやすいから禁止
自然な対策としては、作業ミスを誘発しやすい箇所を識別した上で、括弧付けの規約※などで可読性を確保すればいいのであって、三項演算子そのものの禁止にはならないはず。これについても、数ある言語要素の中でなぜ三項演算子だけが槍玉に挙げられるのか分からんが。
※ Sun のJava規約みたいに 2項演算子を含む条件部を括弧でくくるなど
★ 三項演算子が嫌いだから禁止
三項演算子を使う理由を「好きだから」という情緒によってしか説明できない人と同じくらい、知的作業に向いていない。よって、この手の輩はコーディング規約策定には関与すべきでない。
なーんて、なぜか書いているうちにエキサイトしてきて、文章にトゲが入ってくる・・・
やはり三項演算子談義には、何か人の攻撃性を刺激するような魔物が住んでいるのか・・・
それに対する「使う」派の主張もたまに見かけるが、
- 「控えめに使うなら許されるべき」なんて消極派だったり、
- 「三項演算子すら理解できない奴はクズ」なんて議論拒絶派だったり、或いは
- 「三項演算子の方が格好良くて好き」的な頭脳労働苦手派であったり
自分は使用肯定派だけど、なるべく合理的に三項演算子について考えてみたい。日曜なのに暇だしな。
最初にまず、「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?]
副詞と形容詞の違いで、正当性を表す”right”がどの語に掛かるかが違ってくる(日本語に訳すと何故か鮮やかさが無くなってしまう・・・)。
この functional test と unit test の違いについては、開発プロセスについて決定権を持っているようなポジション人ですらよく分かってなかったりして、いろんな現場を渡り歩いているとたまにガッカリする事がある。
よくある誤解は、「xUnit を使ったら、そのテストは unit test」、「xUnit を使うから unit test」ってやつで、目的と手段が逆転しているパターン(別に NUnit でfunctional test も普通にやるし)。
さらにその上、自動テスト全般と xUnit を混同してる人もいて、「UIの unit test には TestComplete を使うから、Windows Forms のコードには テストコードは書く必要はないです」なんてメチャクチャな主張を聞く事もある。「結合テストをやるから単体テストはやりません」ってのと同じなんだが・・・
「コードが正しく動いて正しい事を実行している」って事のテストは、二つ別々の観点から別々に為されなきゃならないのになあ。
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() について、、、
こんな感じですっきり書ける。アトリビュートを見ると分かるとおり、NUnitではなく MS のユニットテストフレームワークを使っている。テストコードだけ見るとTypeMockよりシンプルかもしれない。
ただ *.moles というファイルで、"Mole する"クラス、即ちモックオブジェクトによって本物オブジェクトの呼び出しを迂回させるクラスを、アセンブリと共に指定する事になる。(ここで指定されたアセンブリに対応して、Moleされたクラスを含むアセンブリが VisualStudioによって自動的に生成されて、プロジェクト参照に追加される事になる。)
あと、Typemock と比べて困るのは、Visual Studio の UnitTest 機構と連動させる形じゃないと、いろいろ手間がかかるらしい事。ってか、NUnitと連動させて動かそうとしたけど、全然上手く行っていない。TestDriven.NETとの連携も、果たしてできるのかできないのか何だか良く分からん。
今の現場は VS2008 の standard で、UnitTest が付いてないので、導入は難しそう。そういえば、導入しにくいのは 有料の Typemock もそうだった。
なーんか、.NETって面倒くさ・・・
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(); } }、、、以下の観点でホワイトボックス・テストする事を考えた
- Main()メソッド内で、引数の先頭要素が Class1 コンストラクタに渡されている事を検証する
- 生成した Class1インスタンスの ShowName()メソッドが呼ばれている事を検証する。
- 但し、実物の ShowName()は、ユーザインタラクションを含むので呼ばれてはいけない。
[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日間くらい朝から晩まで、割と必死に過去問を解いた。
こんな点数になった
午後Ⅱの小論文は、問1の「システム開発プロジェクトのリスク対応計画」を選択して、アジャイル開発プロジェクトをネタにして書いた。
設問では、対象プロジェクトに内在するリスクとその分析、またリスク対応計画とその実施状況が問われたが、これが結構アジャイルと相性が良かったりする。個人的にも日頃から、「今時ウォーターフォールなんてやる人達って、その時点でリスク意識に問題があるのでは?」なんて疑ってしまうタイプなので、割とアジャイル+リスクは書きやすい。
ただ、終了前7・8分になってから、少なくとも600字書くべき設問ウの解答を400字しか書いていない天然ボケに気づいて焦った(そうか、これで去年も・・・)。終了30秒前くらいで200字書き足して、滑り込みで助かった。作文としてはちょっと酷かったかもしれないが、「問いに対する応答」としては一応何とかなったらしい。
それにしてもPM試験に限らず、情報処理技術者試験というとウォーターフォールってイメージだけど、反復型の軽量プロセスでもOKらしい事が分かって良かった。品質/コスト/納期とリスクについての問題意識をしっかり確立した上で、その処方としてのアジャイル導入であり、かつプロジェクト管理の視点でその効果を合理的に語れるなら、マイナス評価にはならないと言う事だと思う。
むしろ現実の業界で、未だにアジャイルについてルーズでアバウトでアナーキーなイメージを持っている人が多くて、こっちの方がよほど問題だ・・・
勉強は、午後Ⅰの過去問のみを徹底的にやった。午前Ⅰは常識問題だし、午前Ⅱは去年勉強済みなので無勉。午後Ⅱの小論文は前回は採点されなかったので若干不安だったが、これも去年かなり練習したので今年はぶっつけ本番とした。
その代わりに、前回少なくとも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らしい事が分かって良かった。品質/コスト/納期とリスクについての問題意識をしっかり確立した上で、その処方としてのアジャイル導入であり、かつプロジェクト管理の視点でその効果を合理的に語れるなら、マイナス評価にはならないと言う事だと思う。
むしろ現実の業界で、未だにアジャイルについてルーズでアバウトでアナーキーなイメージを持っている人が多くて、こっちの方がよほど問題だ・・・