2015年7月10日金曜日

発行者と購読者

現代の実装は確実にスコープを狭めるという方向に向かっています。

この言葉に、ピンと来ない方は少し視点をずらして構造を観察してみることをお薦めします。コードの観察ではなく、構造の観察です。
pub-sub実装は、もしかしたら、おそろく気がつかないところでその恩恵を受けていると言ってもいいと思います。

たとえば、XAMLで画面を作成する場合、この種の作り方としては最も鋭角的なスタイルの実装になるかもしれません。ここではデータの流れをラッピングする形で覆い隠してしまいます。まるで細かいことに固執するなよと言わんばかりです。

たとえば、JavaScriptのMVVM系の一連のスタックは非常にしなやかにデータの流れを隠しています。ここにはアウトプットの「視点」は存在しません。と言ったら言い過ぎかもしれませんが、非常にうまくラッピングされてると言えます。

これらの構造は、GoFのカタログにある古典的なオブザーバー・パターンの思想がベースになっています。まさに先人たちの知恵の賜物です。
現代の要求は非常に複雑になっています。従来のような命令を発行してパラメータを渡す。命令の中はブラックボックスでやがて返却値として回答が返る。受け取った回答をたとえば画面に反映する。と言ったような一連の流れでは難しくなり過ぎています。
この難題を確実に解決するにはどのような工夫が効果を上げるでしょうか?

冒頭に示したようにスコープの分断が有効な手段であることを確認してみてください。
つまり、画面からの入力はパラメータとして処理のブラックボックスに渡します。ここで気を使うべきは、いかに正しい入力をブラックボックスに渡すか?という一点です。
何が返されるか? といったシナリオの終着点は最早存在しません。なぜならスコープの外だからです。
そしてもうひとつの視点が返却されたデータです。ここでは回答が取り出される部分がインプットにあたるという立場をとります。画面には、たとえば DataSource のようなインスタンスの参照を持ち、取り出された回答は DataSource にインプットします。考え方としては入力という視点です。画面にどのように反映されるのかは、ここでは注意を払いません。

画面の制御は極めて難しいものと言っていいと思います。その複雑さにおいて人が注意を払える限界点を超えたところでバグに汚染されてゆくのです。
したがって、私たちはその複雑さを軽減すべく、スコープを分断して注意を払うべき対象を狭めていくのが現代の工夫なのです。

2015年7月8日水曜日

恣意的なロギングの価値とは?

よく恣意的なログを見かけることがあります。
まるで粒度が揃っていなくて何に主眼を置いているのか理解に苦しむ類です。
さらに悪いことに、巷では通称エラーログと呼ばれたりもします。
果たしてこのようなログが役に立つのでしょうか。
エラーを抑え込んでログとして担保されているのであれば、論理的に障害など起こるはずがないと考えるのは、実は自然なことです。
システムやソフトウェアに何か予期しない障害が起きて、ログを調べることが多くあると思いますが、「なんでこんなにも役に立たない情報ばかり出力しているんだ!」と憤然とした経験を持っている方も多いと思います。

このような事象の原因は多くの場合ロギングポリシーを策定していないことが大半だと思われます。そのような状況で各実装の担当者に頼りきってしまえば、属人的なロギングコードが記述されるのは明らかです。チームプレーの場合は悲惨です。

そもそもログにはどんな情報を出力するのが有益でしょうか。
エラー時の内容を示す文言でしょうか。
果たして、エラーとは何を示すものなのでしょうか。
想定した値を得られず処理を中断してユーザにメッセージを導出するプロセスを考えてみた場合、概ねこのような現象をエラーとして取り扱うことが多いと思います。
ユーザ視点で立てばこのような考え方は間違いないと思います。では、ロギングの観点で考えてみた場合、これは果たして適切なのでしょうか。
たとえば、上記の想定で処理は中断されエラー・パスを通り、想定通りユーザにメッセージを通知しました。そして、ログにはそのような手続きの結果を文言として具体的な内容を出力しました。
このような充分想定されたパスを踏んだ手続きをログから読み取ったところで、どのような意味があるのでしょう。確かに、ユーザ向けにエラーとして処理されました。という証拠にはなるでしょう。
しかし、ログの重要性や有益性はもっと別なところにあるはずです。
想定しない制御が起こり、調べる段階でこのようなわかりきった記録を読んだところで、実際はほとんど役に立つことがありません。
なぜならば、客観性に乏しい記録に他ならないからです。
そうです。ロギングのポイントはシステム内のデータを客観的な視点で淡々と出力することが望ましいのです。
おそらくここが難しいポイントでもあるのだろうと思います。
開発者の視点でロギングコードを記述すると、つい当たり前のポイントに目がいかなくなります。障害というのは当たり前のデータの流れの中で起こるものなのです。その当たり前だろうと思っている材料を失うと、それは大きな損失に繋がります。

ぜひ、皆さんも自身のチームのロギングポリシーをいまいちど考察してみてください。

テストの終わりとは?

よくこんな相談を持ち掛けられます。
「どこでテストを終えればよいのか?」
「品質の可否はどこで見極めればよいのか?」

実は、これは見当違いな質問に思えます。
なぜならば、テストは極めて能動的な行為であるからです。
正確に言うならばテストに終わりはありません。理論的には、いつかは、どこかのポイントで終わりを迎えることになると思いますが、そこまでに到達するには天文学的なテストケースを導き出さないとならないでしょう。
もちろん、これは現実的ではありません。

では、最初の質問にあえて答えるとするならば、テストの終わりはどこにあるのでしょうか。
テストの終わりははじめに決めておくべきことなのです。
別の表現を借りるならば、この答えはテストの方針です。品質のスコープと着地点を明確にしておかなければ可否の判断などできないのです。

しかし、ある人は 「それでは、本当に品質をクリアしているのか判断できないではないか。」 と言うかもしれません。
合理的な根拠をもった指標を決めないと、こういう意見がでるのも当然だと思います。さらに言うならば、テストのモニターを怠っているからこその感覚だとも言えます。

もう一度言います。テストは極めて能動的な行為なので、テストをこなしさえすれば品質を稼げるという発想は止めるべきです。
システムやソフトウェアに完璧な状態などあり得ないのです。そのためにポイントを明確にした品質の観点や領域で少しでも指標に近づく努力に力を注ぐべきなのです。

2015年7月7日火曜日

あせるべからず…

仮に  Result オブジェクトで任意の情報(もちろん結果)をプレゼンテーションに返却することを仮定してみます。
Result オブジェクトにはフィールドとして ResultType を保持しているとします。その ResultType が取り得る値は、
Unknown: 初期値
Success: 成功
Failure: 失敗
と定義するとします。
さらに Result オブジェクトは、Results<IEntity> というパブリックアクセサを通じて、内部に保持する「結果」のコレクションにアクセスすることを定義します。
つまり、これらの情報によりプレゼンテーションでは、問い合わせの成功/失敗、そして得られた結果の集合を取得できるようになりました。

一見、理路整然とした構造のように見えます。
では、Aさんにプレゼンテーション層の実装をお願いして、Bさんにモデル層の実装をお願いすることにします。
例題として、蔵書管理の中から任意の作家に関する書籍のレコードの集合を取り出すことを考えてみます。
正常系として、想定した書籍のレコード群が取り出されるわけですが、当然ながら 0件以上  n件 というレコードの集合が取り出されることが考えられます。

では、まずプレゼンテーション担当のAさんの視点で捉えてみます。
たとえば、10件のレコードを取得することができました。ResultType = Success で結果は成功です。同様に1件のレコードのみを取得できました。これも成功です。ここまでは何も問題はありません。
次に0件のレコード、すなわち、検索の結果がマッチせずに結果が返されることを想定します。レコードが返されないので処理は失敗とみなし、ResultType = Failure と考えました。
同じシナリオを、今度はモデル層を担当するBさんの視点で捉えてみます。Bさんは何件のレコードを取得できようが結果は Success で定義できる、という考えをポリシーとして持っていました。つまり、結果0件であろうと、処理そのものを失敗しているわけではないので、ResultType には Success をセットしたのです。
ここに1件のバグが入り込みました。

この場合、どちらの実装が正しいのでしょうか?

答えは、どちらも正しいです。
そして、どちらも間違っています。

両者には、大局的な視点での実装方針を確認しあう 「ゆとり」 が、ほんの少しだけ欠けていたのです。

2015年7月4日土曜日

失敗の経験値

経験を積むとはいったいどういうことなのでしょうか。
たとえば、何かのプロジェクトに参画をしたことにより、それは経験につながるのでしょうか。
正確に言うと、経験を積むとは失敗を重ねるということに他なりません。
ただし、注意しなければならないのは、失敗を重ねることの字面をそのまま受け取ってはいけないということです。失敗は単なる失敗でしかないからです。
重要なのは、失敗の背後にはたくさんのヒントが隠れていることを認識することだと思います。
わかりやすく言えば、失敗の経験を基に成功が導き出されるのです。逆の言い方をすれば、つまり、失敗は成功の根拠になるのです。
成功を表すには根拠が必要です。その根拠とは失敗の裏返しです。
何かの仕事で成功を勝ち取ったとしましょう。しかし、その根拠を言い表すことが出来なければ単なる「まぐれ」です。失敗の理由すらそこから導き出すことはできません。
言い換えると、それは経験には至っていないと考えなければなりません。

もし、皆さんが現在従事しているプロジェクトがあるならば、その仕事を終えたときに、チームのメンバーとともに、ぜひとも反省会を開いてみてください。
そして出来るだけたくさんの失敗談を列挙してみてください。
その失敗はなぜ起こったのか? どこに原因があるのか? 必ず分析をしてみてください。
そこではじめて経験を積んだことになるのです。

2015年6月13日土曜日

1/1の配慮

たとえば、
あなたがずっと欲しかったものをやっと手に入れたことを想像してみましょう。
何でも構いません。出来れば幾分高額なものがよいでしょう。イメージしてみます。
喜び勇んでわくわくしながら帰宅したあなたは、その欲しかったものの使い心地を早速試してみます。
なるほど、あなたの見識眼は見事にその欲しかったものをぴたりと当てました。まるで、あなたの人生に光を照らす光明のような商品でした。
その使い心地をさらに確認すべくあなたは、いろいろと試してみることに余念がないことでしょう。
ところが、どうしたことか、そのものは暴走を始めてしまいました。思慮深いあなたはもう一度同じことを試してみます。するとどうでしょう。再び同じ現象が起こりました。確信を得るためにもう一度使い心地をゆっくりと振り返りながら試してみます。確実に再現することを、あなたは認識しました。
ここまでで、あなたの心は打ちひしがれてしまうことでしょう。長いこと欲しかった製品の不具合を発見してしまったのです。

さて、初期不良かもしれません。いずれにしてもあなたの想定を深く裏切られてしまったことに変わりはありません。まさに絶望を味わうことでしょう。
あなたは、この商品を作ったメーカーを許せるでしょうか。返品や交換には応じてくれることとは思いますが、あなたの期待は裏切られてしまったのです。

こういった現象は常に起きうることです。しかし、あなたは、このことを許せますか?
ユーザーは商品に対して常に希望を抱き、ときには夢を持つものです。しかし、この期待感はまれに裏切られる結果となることがあります。

今度は逆の立場をイメージしてみます。
あなたは、ソフトウェアのエンジニアです。
ユーザーの希望や夢を実現すべく、工夫に工夫を重ねて素晴らしいパフォーマンスを発揮する便利なソフトウェアを作り上げました。
そのソフトウェアをお客様に届けることを、出来るだけ具体的にイメージしてみてください。
お客様は使い心地をひとつひとつゆっくりと確認していきます。ひとつのイメージを想定しつつ、その結果を確認しながら、自分の希望が実現されている便利なソフトウェアに心躍る気持ちです。
ところが、ひとつのタイミングで結果が得られないという現象が起きました。お客様は疑問を持ちながらも、まだ消えていない希望の気持ちを維持しつつ、もう一度同じことを試してみます。今度は結果が得られないばかりか、反応さえ失われました。いわゆるフリーズ状態です。ここまできてお客様は不具合の確信を得ました。

あなたの作ったソフトウェアに不具合が存在したのです。
ただの不具合ではありません。さきほどあなたが経験した幻滅や絶望を、楽しみにしていたお客様に与えてしまったのです。

このようなことは比較的簡単に起こり得ることです。
あなたは、このようなイメージを常に持ち続けているでしょうか。

このようなイメージ、想像力、配慮を持ち続けることはとても重要なことです。
モノづくりの分野でよく言われることは、大量生産の世界で歩留り95%を叩き出せればかなり効率が良いと言えます。しかし、お客様のもとに届く製品は常に1/1の100%であるはずです。
これはどういう意味を持つことなのか? ここに想像力たくましく配慮をすることは、実はとても重要なことなのです。

2015年5月20日水曜日

WPFのRichTextBoxで文字数を制限する

※ 疑最適解の謎ポストですお許しを WPFでアプリケーションを作っていて、トレースログをUI上に表示する機能が必要なことが結構あります。ほとんどの人はそんなことないと思いますが、私にはあります。
そしてトレースログなのでERRORとかWARNINGとかINFOとか表示するので、漢の私は赤とかオレンジとかボールドとか使って味気ないログを華やかに彩りたいと思うのです。
するとUIにはTextBoxコントロールではなくRichTextBoxコントロールを使わなければいけないのですが、ここで問題が。
そんなに過去のトレースログをご丁寧に画面上のコントロールに持っておくのも精神衛生上よろしくないので文字数に制限をかけたいと考えるのですが、WPFのRichTextBoxにはないんですね、MaxLengthプロパティが。
ですが DeleteTextInRun というメソッドがあるようなので、これを使えば打ち止めの文字数を超えたN文字を先頭から削除するのはちょちょいのちょいだよね・・・

MyRichTextBox.Document.ContentStart.DeleteTextInRun(N);

働きませんな。
何が間違っているのでしょうか、私はダメな人間でしょうか。
そこでGoogle先生に DeleteTextInRun doesn't work と質問したところ海外のQuiitaことStackoverflowやMSDNでも似たようなことでお困りの方が何人かおられましたが、私の求める最適解にはたどり着けませんでした。
しかたないので参考になる文献をベースに修正してTextChangedイベントに実装した結果

private void MyRichTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
    // MaxTextLengthは制限をかけたい文字数です
    TextRange range = new TextRange(MyRichTextBox.Document.ContentStart, MyRichTextBox.Document.ContentEnd);     if (range.Text.Length > MaxTextLength)     {         TextSelection selection = MyRichTextBox.Selection;         TextPointer contentStart = MyRichTextBox.Document.ContentStart;         TextPointer selectionStart = contentStart.GetPositionAtOffset(0);         TextPointer selectionEnd = contentStart.GetPositionAtOffset(range.Text.Length - MaxTextLength);         selection.Select(selectionStart, selectionEnd);         selection.Text = "";     } }

期待する動きは実現しましたがかなり冗長な気がするんです。
いい方法をご存知の方、居たら教えてください。