Windows Live Writer をテキストエディタから開く

Metro アプリストアへの登録記念ということで(単に、登録をだけで、アプリの公開はまだですが)、
Windows Live Writer を外部から操作する tips ということで。

準備としては、以下にあるように

c# – Windows Live Writer Automation – Stack Overflow
http://stackoverflow.com/questions/8490977/windows-live-writer-automation

regsvr32 WindowsLiveWriter.Application.dll

をレジストリ登録。こうしないと、IWindowsLiveWriterApplication2 へのキャストでエラーになります。何故かわからんけど、そういうものみたい。

これで作ったのが以下なコードです。

[img 20120927_01]

20120927_01

の形式で画像を貼りつけることができます。

namespace LiveWriterPost
{
	class Program
	{
		static void Main(string[] args)
		{
			if (args.Length == 0)
			{
				Console.WriteLine("LiveWriterPost [path]");
				return;
			}
			string path = args[0];
			var lw = new LiveWriter();
			lw.NewPost(path);
		}
	}

	public class LiveWriter
	{
		public void NewPost(string path)
		{
			// ファイルコードは UTF-8 で
			var sr = File.OpenText(path);
			// 最初の行はタイトル
			string title = sr.ReadLine();
			// 残りは本文
			string html = sr.ReadToEnd();
			NewPost( title, html );

		}
		public void NewPost( string title, string body )
		{
			string imgdir = @"file://D:\work\blog\image\";

			body = Regex.Replace( body, @"\r\n\[img ([^]]+)\]", "\r\n\<img src='"+imgdir+"'$1.jpg" />");
			// 先頭行を削除
			body = Regex.Replace(body, "^\r\n
", "");
			// 改行を変更
			body = Regex.Replace( body, "\r\n", "
\r\n" );

			var _app = new WindowsLiveWriterApplication();
			var app = (IWindowsLiveWriterApplication2)_app;
			app.BlogThisHtml(title, body );
		}
	}
}

ここのコードの部分は、wordpress 上で [/code] を使って書き直しています。なので、要検討。
あと、リンクの自動設定のところも。

カテゴリー: C# | Windows Live Writer をテキストエディタから開く はコメントを受け付けていません

仕様書の基本と仕組み 第2版ができました

宣伝がてら。秀和システムの「仕様書の基本と仕組み 第2版」の見本が届きました。

図解入門 よくわかる最新 システム開発者のための仕様書の基本と仕組み[第2版]|書籍情報|秀和システム

IMG_0388

基本的な路線は変わらず、増補版という形でボリュームを増やしています。

  • 継続的にアップデートする WEB サイト開発のパターンを追加
  • 携帯アプリなどのパッケージ型の開発パターンを追加
  • 仕様書テンプレートを追加

しています。まあ、アジャイル的に言えば、仕様書、設計書は必須という訳ではないのですが、取り処としてちまちま作っておくと便利です。特に、複数名のグループであったり、外注をしたり、あるいは外注を請けたり、というところでは「契約面」も含めて、仕様書が必須になります。

この本の中では、仕様書(specitication)と、設計書(software design)の区別をあまり明確に解説していません。いくつかの WEB サイトや現場でもこの区別は曖昧なのですが…まあ、曖昧でもいいんですけどね、それは現場に応じて。区別をするならば、仕様書が「顧客からの視点」で、設計書が「開発メンバからの視点」ってことです。これは、ひとり開発や自社開発でも同じことで、

  • 外側から制約を掛けるもの。必須となる条件や機能のことを「仕様書」に書く。
  • 「仕様書」の機能を具体的にプログラムコードまでに落とすまでを「設計書」に書く。

という区別にしておいたほうが良いです。これは、仕様書、設計書という名前にこだわるのではなくて、「何を作ればよいのか」、「今回は何は必要ないのか」という「作業量」の問題ともなり、契約の線引きにもなります。このあたりが曖昧のまま進むと膨大な無駄コードを量産してしまうことなるので、注意が必要です。が、まぁ、現実的には、そういう線引きも必要なんですが、「作業工数」という人月的な面もありますからね。工場のラインとは違って、

  • 作らなくて、他から持ってくることが可能
  • ここで作っても、使わない可能性がある。
  • 他で使うために、ここで作っておく

というパターンがありますからね。そのあたりの話はまた別途。

仕様書のテンプレートに関しては、Word/Excel 2010 で用意をしました。先の秀和システムさんのサポートページがからダウンロードができます。使いどころや説明に関しては、書籍をご覧ください。ちまちま自分で使っているものを多少改変してあります。

カテゴリー: 書籍 | 仕様書の基本と仕組み 第2版ができました はコメントを受け付けていません

GBC を見て「重力」な機構を考える

LEGO TECHNICからくり部屋 レゴ GBC 二年間のまとめ
http://legokarakuri.blog91.fc2.com/blog-entry-48.html

海外で反響が…ってのを見て、このバスケットの部分は確かパクリだよ…と思っていたら本人でした、という話。玉入れのところを以前みて、注目しておりました。

自分のほうは、OpenCV で画像解析、プチロボを使って6軸のアーム作りの組み合わせをしたいところで、これに .NET Micro を組み合わせる予定です。ソフトウェア関係は長年やっているので OK なのですが、機器関係がまるで駄目で、多少の半田付けやプラモデルレベルの集中力が失われつつ…な状態なのですが、これを見て再び、絶賛挫折中の6軸アーム作りを頑張ります。

clip_image007

どれを見ても飽きないのですが、飽きずにみていると、分かるのが、

  • ボールが途中で滞っていない。
    • ボールを送るスピードが同じである。
    • あるいは、若干初速が遅くて、最後が早い、という作りになっている。
    • 生産系の TOC みたいで面白い。
  • 回転動作を、左右やカムの動作に切り替えている。
    • 機械工学の基本なのだけど、原子力屋さんの私はやらなかったのよねぇ。
  • ボールを送るのに、「重力」を活用している。

なところです。生産ラインの設計をしている方には当然なのかもしれませんが、ソフトウェア工学の場合には、この手の「製造段階の繰り返し」というのがきわめて少ない(多少の自動生成はありますが、ソフトウェア開発の「製造工程」は事実上、CD-ROM 焼き工程だったりするので)ので、このモーターの回転のみを利用して「繰り返し動作をさせる」ところに非常に興味が湧きます。

品質工学を見ると分かるのですが、生産ラインの繰り返しは、必ずしも「均一」ではありません。いわゆる、歩留りと言われる不良品がでます。この不良品率をできるかぎり「0」に近づけるのが、シックスナインな品質な訳ですが、実は微視的に言えば「歩留り」には至らない(不合格品には至らない)許容範囲のゆらぎを確保しつつ、生産ラインを作ることが、実は「安定的な生産ライン」を作ることと同値になります。

揺らぎ自体は、この GBC のような、完全オートマチックなもの(人手を介在しない)もあれば、途中に人手が必要なものがあります。あるいは、ゴールドラット氏の言う「ザ・ゴール」(だったっけ?)の中にある、機械のセッティングに掛かる時間を考慮する場合もあります。

なので、実は、品質を上げるという中には、経営的な意味も含めて考えると、

  • ライン自体を安定稼働させるシステム
  • ライン以外の揺らぎを許容するシステム

の2つが必要なわけですね。

さて、この GBC を眺めていると、ボールが順々に送られるわけですが「途中で滞る」ことはありません。実にスムースにボールが送られているわけですが、それには安全工学的に非常に重要な「重力」の問題がうまく解決/利用されています。作った彼がそれを意図していた(と私は思う)のですが、先の図のように、重力は常に下に向かって働きます。

ここで、一番最初のボールは「傾斜されている、スロープに沿って、輪の中へ送り込まれます」。ここの「傾斜」が枠に入れる仕組みである。ボールが1個ずつ送り込まれる仕組みです。そして、回転する輪は、少しだけ斜めになり、ボールは外側に落ちないで上に上がってきます。最後に、斜めになった向こう側に穴が開いていて、そこに「重力」が働いて、ボールが輪から出ていくのです。

すごいよ、akiyuky さんは完全に意図的にやっているよッ!!! と偉そうにほめまくりたいです。

この手の「実学」は、おそらくたくさん作った中で培ったものであり、電子回路をたくさんつくると大体勘でコンデンサーや抵抗の計算ができるそうで(そうらしい)、かつ安全用のゲートもそれなりに作れるそうで(確かに、電子回路の本をみると「○○の安全のために、○○を入れておきます」っていう文が頻発するのです)、そのあたりは「職人芸/勘」の世界です。ここでは「職人芸」と言ってしまいますが、実は「実学」としては大学の座学なんて目じゃないんですよね~。ええ、体系的な理論も必要なのですが、モノを作るというのは、目の前の「現実」に向き合うということなのですよ。

~~

そうそう、画像解析の「実学」も似たところが多くて、動物の「目」を理論的に解決するところからのスタートと、なんとなくマッチングすればOKというコンピュータらしい力技なところもあります。どっちにせよ、「現実」の解決になればよいわけで、識別する対象によって適切なロジック(それが簡易ロジックであってもよい)を満たせば十分「目」に足るということです。顔認識や、テンプレートマッチングなんてのは、力技のほうですよ。

カテゴリー: 開発, 雑談 | GBC を見て「重力」な機構を考える はコメントを受け付けていません

じりじりと Metro Design について考えていこう

そろそろ Metro Design について考えてみよう | Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/3660

の続きです。

Metro スタイル アプリの構築方法を学ぶ
http://msdn.microsoft.com/library/windows/apps/

なところで、日本語版は「Metro スタイル」になっていますが、まあ「Windows ストア」スタイルでも何でもよいのです。ここに書いている話は「話半分に」聞いておかないと、後でドハマりいたしまっせ、って具合なのです。「ユーザーの価値が~」というのはさておき(自己言及すれば、「Windows 8 のユーザーに対する価値は~」という縛りなんですから)、Metro Design について引き続き考えていきます。

■まずは、Metor スタイル ガイドラインの読み方を

これは、Microsoft社の悪いところですが、本来の目的を忘れて手段に興じてしまうところがあります。Oracle のドキュメント群は昔から非常に少なくて辟易するものですが、あれはあれで Oracle の戦略としては重要なのです。「ガイドライン」には、先の記事に書いた通り「先駆者」を模倣する側面があるので、そのあたりを殺ぎ落として読むのがベターです。

私の場合、「組織」から離れて長いので、このあたりが見えるのですが「組織」に入っている人は、意外と見えにくいものなので注意が必要ってことで。まぁ、「組織」に組み込まれている人はそれはそれでいいんですが、フリーな人が、これにハマるとちょっとアレかなと。

  • ユーザーの価値、アプリの価値に言及したものは、読み飛ばし。
    • これは、開発者/開発する経営者が決めるものですから。
  • デザインの価値も読み飛ばし。
    • タイポグラフィとか、色デザインの本に直接あたったほうが良いです。
    • あと、iPad とかを使ってみるとか。
    • 中世のイコンなんかを調べると良いです。
  • コンテンツ操作のなんちゃらの話も読み飛ばし。
    • コンテンツの質や量によって変わります。また、読者によっても。
    • ターゲットの「引っ掛け」具合によっても変わります。
    • Metro アプリの場合、全画面が普通(単一画面)になるので、独自操作を作ってもそれほど「違和感」はありません。
  • 設計ガイダンス、UI の作り方
    • これは、アラン・クーパーの本とか、D.A.ノーマンの本とか読んだほうがいいです。
    • 読んだ上で、戻ってくるならば良いかと。
    • デザインルールは「審査が通る」程度でOKです。そのうちぐだぐだになるのを期待してます。
    • よく分からない場合は、先行する iPhone アプリの真似をするのが良いです。
  • サスペンドからの復帰に関して
    • これは「考慮不足」なので、読み飛ばして OK です。
    • おそらく、きちんと実装できるアプリケーションは現れません。

ってな感じで「読み飛ばし」て良いところがたくさんあります。

開発者/経営者として重要なところは、

あとは、ざっと流し読みをしておけば OK です。某所の本は、この主旨で目次をまとめてあります。

■ Metro Design の原点に戻ると

実は、先に書いた通り「読みやすい」かどうかは、「読みやすくさせるかどうか」はコンテンツの種類に変わっていきます。D.A.ノーマンは、航空機についているTV操作について、「子供がゲームをしたいと覆ったら、どんな複雑な操作でもこなしてゲームに辿り着こうとする」訳で、多少の複雑さはものもしません。しかし大人が何かの商品を買おうと思ったら「ちょっと複雑な操作をするぐらいだったら諦める」のです。このあたり、ゲームと商品販売が大きく違うし、読書にしても実用書と小説の場合は違うし、漫画だって流し読みしたい場合と、じっくりと考えながら読みたい場合もあるので、色々あるのです。だから、商品ごと本ごとに「パッケージ/装丁」がある訳で、それに惹かれるなり、その品物のデザインなりを重視して「購入する」に至る、あるいは「利用する」に至るわけですよ。「利用する」と「購入する」をあえて分けているのは、「購入するけど利用しない」パターンもあるからですね。現在のような経済の場合は、このパターンが一番「販売効率がよい」ことになっています。

で、PC タブレットや、各種のスマートフォンの場合は、外側のパッケージ部分は一様になってしまいます。もちろん、機種自体はユーザーが選べるのですが、アプリは機種の外観を変えることを(いまのところは)できませんよね。同じアプリを作っても、iPhone で動かす場合と、Windows 8 タブレットで動かす場合では、違ったアプローチをしたほうが良かろう、ということが容易に想像できます。

なので、一概に Metro Design は?ってことになると幅広くなってしまうので、ひとまず、電子書籍について考えてみましょう。

■ Metro Design としての書籍はどうなるのか?

先に書いた通り、電子書籍にしても色々あります。実用書、漫画、ライトノベル、コンピュータ本、占い本、株式投資本、絵本などなど。実のところ、大江健三郎の本とか、カフカの本を iPhone で読む気にはりませんし、IT 業者としてそれらの本を「電子書籍化」したとしても儲かりません。ええ、青空文庫的に「なんとか読める」ようにはなるのですが、いまのところ若い人以外は真面目に読むことはしないでしょう。一部の本好きのマニアだけです。先行き、教科書の電子化などが進んで、画面自体に慣れていけば、もうちょっと違う感じになると思うのですが、そうなると「本」自体のスタイルが変わってしまうので、ここでは「今、電子書籍化できるもの」かつ「収益が見込めるもの」を対象としておきます。

そうなると、いわゆる「読み捨て」のビジネス書は、電子書籍の筆頭にあがってきます。1回読んでBOOK OFF に売り飛ばすか(あるいは、BOOK OFF から買ってくるか)という感じで、数年後に読み直すことはありません。ならば、本を家においておくよりも(最近は本棚のない家庭があるので)、通勤途中にさっくりとダウンロードして、さっくりと読み捨てるというスタイルで「読める」ほうがよいわけです。

なので、ビジネス書を読むときのスタイルとして、

  • さっくりとダウンロードできる容量にする。
  • 文章をぱらぱらと捲れるほうがよい。
    • できれば、ページ数をなんとなく覚えておくほうがよい。
  • ラインマーカーをつかいたい。
  • 読み終わったら関連書籍を購入、という購入チェーンが望ましい

のパターンが良いのです。電車を待っているときにダウンロードが終わる容量と言えば、10M弱位でしょうか。このぐらいだと、図版を入れると重くなる(白黒ならば大丈夫か?)ので、できる限り文章だけで済ませます。大体の新書は、2週間ぐらいで書きあげてしまうので、図版は全くないか、チープなものしかないのが普通です。ページ数は、既存の新書よりも少なくて構いません。iPhone の画面は小さいので、文章が少なくてもページ数が増えたように見えます。ダウンロードさせる時には、躊躇する値段(1,000円とか)は避けたほうがよいです。500円ぐらいの漫画の単行本ぐらいの値段がいいですね。漫画雑誌の値段 300円位でもいいと思います。要は、「読み捨て」ができるスタイルにします。長い文章であれば、コストダウンを目的に分冊してしまいます。

文章の脇は、新書と同じように多めに空けておきます。文字を変更できると良い、と思われれかもしれませんが、変更できなくても構いません。その書籍にマッチしたフォントだけを指定すれば良いのです。ページ数は、読んでいるときに左下あたりにでかでかと表示して構いません。小説とは違って、読み飛ばし、斜め読みが普通なので「ああ、あれはたしかここに」というなんとなく覚えるマーカーがあれば十分です。

巷の電子書籍リーダーではマーカーの使い方が駄目です。まさしく蛍光ペンで、適当なところに○なり線なりを指で付けられるようにします。プログラムとしては、レイアウトは変わらないのですから、ページ数と位置情報だけつけておけばOKです。

ツイッターなりフェイスブックなりに投稿する機能は必須です。連携するだけでOKです。「○○本の何ページ目」な形で投稿できるとなお良いでしょう。他の人に購入を諭すのではなくて「興味」を持たせるのが、広告業界の基本ですよね。

読み終わったら、関連書籍にジャンプさせましょう。続きものにして別ジャンルに飛んでもよいです。しかし、やり過ぎてはいけません、あくまで読者が「うーん、今度買うとしたらこれかな?」という感じで amazon のほしいもの、を集める機能があればベターです。これは他の機能と連携しても OK です。

…と、こんな風に「Metro Design」は考えるわけです。地下鉄のデザインは、地下鉄を利用する人の立場になって考える、というスタイルでもありますが、同時に、自然発生的にでてきたものを極力削り落として、裏の目的を果たさせる(道路標識は、事故を減らすという大きな理由がありますよね)のです。そのなかで出てきた、グリッドスタイルであったり、Metro 的なデザインであったりするので、進化論とか、自然淘汰とかの話になりますね。ええ、天地創造の方には理解されにくいかもしれませんが。

こういう風に考えていくとですね、グリッドの幅とか、フォントの大きさとかは「パターン」でしかないことが分かります。「某ガイドライン」では色々後付をしていますが、要は進化により帰着したデザインをシミュレートしたデザイン、ってことになるのです。それは、営業的には「先駆的なデザイン」を主張することになるのですが…まあ、そのあたりは Microsoft の戦略ということで、大目にみましょう。このあたりの話は、C.アレグザンダーの「パタン・ランゲージ」を読むと分かります。オブジェクト指向、GoF として有名になった「パターン」ですが、原本に立ち返ってみると、その後のパターンがポストでしかないことを分かります。

ちなみに言うと、この電子書籍のパターンは「ビジネス書」の場合にあてはまります。漫画や、子供をあやすための電子絵本の場合は別なアプローチになります。

カテゴリー: windows 8 | 1件のコメント

[C++] NULLポインタアクセスをMFCはどのように回避して…いないか。

null/nil の扱いをオブジェクト指向的に考え直す | Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/3770

なところで、Objecitve-C の nil の「優れた」扱いについて書きましたが、実は MFC(Microsoft Foundation Class)にも NULL ポインタに対して「優れた」扱いをしているのです、という話をひとつ。

MFC ってのは、Windows アプリケーションを作る時のクラスライブラリで、似たようなものには Delphi のライブラリがあります。ウィンドウシステムを扱うときに、直接の Windows API を扱うよりもクラスを使ったほうがまとまりが良い、ってのが主旨ですね。これを押し進めたのが、Windows RT なんですが、またこれは別の機会に(というか、この話はあちこちで出ているので)。

オブジェクト指向の扱いとして、MFC が行った実装は、CWnd クラスになります。

CWnd クラス (MFC)
http://msdn.microsoft.com/ja-jp/library/1xb05f0h(v=vs.80).aspx

CWnd クラスってのは、あらゆるウィンドウの元のクラスになっていて、これは Windows OS が、ウィンドウハンドル(HWND)を必ず持っている、という前提から来ているものです。後に、WTL というテンプレートライブラリで作ったウィンドウクラスライブラリもある訳で、必ずしも HWND が必要という訳ではないのですが。
CWnd クラスは、内部的にひとつのウィンドウハンドルを持ちます。CWnd::m_hWnd という形で保持しているのですが、このメンバ変数へのアクセスは、CWnd::Attach, CWnd::Detach という特別なメソッドを使います。あるいは、ウィンドウを作るための Create メソッドを使います。

ここで、CWnd 自体と、内部の CWnd::m_hWnd の動きを見てみると。

CWnd wnd ; 				// m_hWnd: NULL;
wnd.Attach( hwnd );		// m_hWnd: hwnd ;
...
wnd.Detach();			// m_hWnd: NULL;

という感じになります。クラスとして m_hWnd を内部に持っているために、外部としては常に CWnd オブジェクトを持ち続け、Attach/Detach により 内部の m_hWnd を設定する≒遷移するという仕組みです。

さて、ここに CWnd::GetClientRect というウィンドウの矩形の大きさを取るメソッドがあります。GetClientRect メソッドは、内部的に m_hWnd を参照して、Windows API の GetClientRect 関数を呼び出すという仕組みになっているので、コードとしてい次のように書きます。

CWnd wnd ;
wnd.Attach( hwnd );
CRect rc;
wnd.GetClientRect( &rc );
...
wnd.Detach();

GetClientRect 関数は、必ずウィンドウハンドルを必要とするのですが、CWnd オブジェクト自体が NULL でなければ、次のように Attach 前の場合にも呼び出しは可能です。

CWnd wnd ;
CRect rc;
wnd.GetClientRect( &rc );
...

さて、このとき rc は何を期待するのでしょうか?
内部のウィンドウハンドルが初期化されたまま NULL のままなので、矩形の大きさの取得自体が無効です。無効ではありますが、あえて返すとすれば、{0,0,0,0} の無効値を返すのがよいでしょう。

ここで面白いのは、ラップしている CWnd クラスと、ウィンドウハンドル自体の m_hWnd の関係です。ウィンドウハンドルに関わるメソッドについては、CWnd オブジェクトからの呼び出しは可能であるのですが、内部の m_hWnd が NULL の場合は「アプリケーション例外」を発生させるべきかどうか?という問題がでてきます。

そう、Objective-C 風にするならば、m_hWnd の値が NULL の時(Attach する前の時)でも、CWnd::GetClientRect はさらりと呼び出されたほうがよいはずです。そうですよね…

■で、実際のところはどうなのか?

実は、CWnd クラスの内部で、ASSERT( this->m_hWnd != NULL ) という形でチェックをしています。わざわざデバッグモードでは止めてあるのです。しかも、ASSERT はデバッグコンパイルだけ実行されるので、リリースビルドの場合は m_hWnd は NULL のまま通ってしまい、アプリケーションエラーとなります orz

ここのところは if ( this->m_hWnd == NULL ) return ; のように、NULL チェックだけして何事もなかったように値を返して欲しかったなぁと。そうすると、Attach や Create 前に wnd->GetClientRect をしてもエラーにならなくて便利なんですけどね。

カテゴリー: C++ | [C++] NULLポインタアクセスをMFCはどのように回避して…いないか。 はコメントを受け付けていません

null/nil の扱いをオブジェクト指向的に考え直す

Objective-C で nil のメソッドを実行すると例外が発生しないのは変…ではないよ、というのを解説。

■そもそもの NULL の意味

C++ も Objective-C も C言語を発端としているので、「NULL」≒「値が無い状態」というのを継承しています。
御存じの通り、C言語では、NULL というのは(void*)0 あるいは 0 として定義されています。定義されているのですが、これが NULL という意味を示しているかどうかは別なのです…が、「現実主義的な」C言語としては、NULL = 0 のほうが都合が良かったわけですよ。

基本は NULL はポインタとして扱うので、0 ポインタ自体を「有効」にできないという矛盾があります。かつて、8bit 時代の CPU ではメモリが貴重だったので、0 ポインタを「無効」にするとはなんということかッ!!! という話ががあったとかなかったとか聞きます…いえ、聞いたことはありませんが、0 ポインタを特別な値にするのは、結構なもめごとだったのです。当然、アセンブラだと 0 から始まったほうが良いですからね。

ですが、16bit 時代になり、ほどよくメモリが広くなると捨て領域としての 0 ポインタが作れるようになりました。つまりは、先頭の 16 バイトぐらいは捨て領域にしたわけです。これは、NULL ポインタアクセスを検出するためと同時に、NULL アクセスをしたときに OS ごと落ちてしまう(MS-DOSの場合は落ちますが)ことを防ぐために、0 ポインタは「無効」な領域として存在させていたわけです。

そんな訳で、NULL というものが「無効」であると同時に、0 であることを決めたのが「#define NULL 0」あるいは「#define NULL ((void*)0)」な訳ですね。ちなみに、20年以上前の古いコードを見ていくと、この定義が散見しています。これは、組み込み系のCコンパイラが NULL を定義していなかったからなんですね。まぁ、インクルードとして stdio.h に define が定義されているため、というのもあります。

つまりは NULL の定義としては、

  • そのポインタが「無効」である。
  • そのポインタが「0」である。

の二重の定義があるのです。実は2番目の定義がデファクトスタンダードで、なんか NULL を 0 に定義してまったら、定着してしまったという悪習ではありますが、まぁ、そういう二重の定義を NULL は持ちます。

■NULL ポインタをアクセスするという意味

では、NULL ポインタをアクセスするという意味を考え直してみます。
現実的に 0 ポインタにアクセスするということは、実はメモリというものは「メモリがある限りアクセスできる」という原則に従えば、0 ポインタでも何処でもよいわけです。実際、i386 のノーマルなモードではそういう動きをしています。

しかし、i386 のプロテクトモードからメモリ保護の概念が入ってきました。詳細は i386 アセンブラの本を読んで頂くとして、メモリアクセスに「範囲」を指定できるようになったわけです。で、「範囲」以外のときには、アクセス保護例外が発生できるようになりました。この「アクセス保護例外」自体が、まさしく「NULL ポインタアクセス例外」な訳です。もう少し詳しく言えば、0 ポインタをアクセスできるようにしてしまえばアクセス保護例外は発生しないのです。つまりは、あえて 0 ポインタにアクセス保護を掛けている訳ですね。

さて、通常の NULL ポインタのアクセスとしては、C言語ではこんな風に書きます。

int *n = NULL;
*n = 10;

NULL = 0 ポインタを示すので 10 を代入しようとしたときに「アクセス例外」が発生します。

string *str = NULL;
int sz = str->size();

この場合は、どうでしょうか? str が 0 ポインタとなっているので、0 ポインタの size メソッドを呼び出そうとしてエラーになります、という仮定ができます。現在の vector<> では NULL ポインタアクセスのエラーになりますが、実は、こんな風に書くとエラーになりません。

class A {
private:
	 int _n ;
public:
	A() { _n = 0; }
	void func() {
		cout << "in A::func " << endl;
	}
	static void sfunc() {
		cout << "in A::sfunc" << endl;
	}
};

int main( void )
{
	A a;
	a.func();
	a.sfunc();

	A *p = NULL;

	p->func();
	p->sfunc();

	return 0;
}

これを実行すると、エラーを出さずに動きます。 p->func や p->sfunc のところで p が NULL なのでエラーが発生しそうな気がするのですが、実はエラーにならないのです。なぜでしょうか? 実は、先の「仮定」が間違っていて、C++ の場合クラスのメソッドを呼び出すときには、クラス自身の関数テーブルを呼び出し、その中でメソッドのポインタを呼び出すからなんですね。なので、クラス自身の関数テーブルだけを参照するような static メソッドや内部変数を扱わないメソッドはエラーにならないのです。

※ コメントにある通り、ここでは、virtual method を使っていないので実は vtbl は関係ありませんね。ちょっと後でこのあたり修正します。実際、virtual func2 を定義してやって、p->func2 と呼び出すと、this->vtbl が呼び出せないためにエラーなります。

なので、次のように内部変数の _n を参照させてやると、p->func の実行時にエラーになります。

class A {
private:
	 int _n ;
public:
	A() { _n = 0; }
	void func() {
		cout << "in A::func " << this->_n << endl;
	}
	static void sfunc() {
		cout << "in A::sfunc" << endl;
	}
};

ということは、NULL ポインタへのアクセスというのは二つのパターンがあって、

  • NULL ポインタそのものにアクセスする。
  • NULL ポインタを持つオブジェクトのメソッドやプロパティにアクセスする

というパターンがあるわけです。既に分かる通り、NULL ポインタそのものにアクセスする時は「アクセス保護例外」が発生するのでエラーになります。しかし、NULL ポインタのオブジェクトに対しては、C++ では一度クラスの this ポインタにアクセスするためにエラーにならない場合もあるのです。いや、エラーになるのは、内部の this ポインタからオブジェクトそのもののポインタへアクセスしようとした(この場合は 0 ポインタです)

■ちなみに C# の場合はどうなのか?

C# の場合をみてみましょう。

public class A
{
	private int _n;
	public void func()
	{
		Debug.Print("in func");
	}
	public static void sfunc()
	{
		Debug.Print("in sfunc");
	}
}

同じようにクラスを作っておいて、以下のようにアクセスをすると p.func() のところで例外が発生します。

A a = new A();
a.func();
A.sfunc();

A p = null;
p.func();
A.sfunc();

C# の場合は、NULL ポインタそのもの(擬似的に null ですが)にアクセスするために、例外が発生していると考えられます。
ちなみに static メソッドの場合は、クラス名でしかアクセスできないので、A.sfunc のために例外が発生しません。C++ の場合は、A::sfunc でもアクセスできるし、p->sfunc でもアクセスできる、という違いがあります。

■Objective-C の nil の挙動を考える

さて、このことを踏まえて、Objective-C の nil の挙動を考えます。nil の場合は、オブジェクトに値を設定しても「アクセス例外を発生しない」という挙動があります。

 A *a = nil;
 [a func];

この func を呼び出すときには、どのような挙動が望ましいのでしょうか?

  • C++ の static メソッドのようにアクセス例外を発生させない。
  • C# のようにアクセス例外を発生させる。

実は、Objective-C の発祥は古くて、ほぼ C++ と同じぐらい(30年前ぐらい?)です。実は F# の元になっている関数言語も同じぐらいの発祥だったりします(教科書をみるとその位の年代)。なので、プログラム言語のカンブリア紀って感じだったのかもしれません。その後、Perl や Ruby などのスクリプト言語(sed, awk, sh は以前からあるし)にも関係していきます。

そこで、Objective-C としては、C++ の挙動によってアクセス保護例外が発生するよりも、全く例外が発生しない、という道を選んだわけです。これが、nil が単なる 0 ポインタ(NULL ポインタ)ではなくて、オブジェクトとして扱ったときの C++ や C# との大きな違いになります。

# java の null の扱いはどうだったかなぁと思っているのですが … 確かめてみると、C# と同じように p.func() の時にエラーを発生しますね。

■nil の利点を考える

長々と書きましたが、実は nil の挙動に関しては、他にはない非常に有利な点があります。
通常は、オブジェクトの NULL 判別をしなくて便利とか、間違って NULL を渡されてしまったときもエラーにならないくて便利、という「便利」さが強調されていますが、実は、もっと大きな利点があります。
この「利点」どの本にも書いてないので、もともと objective-c の発想にあったのかさだかではないのですが、解説すると、

スレッド間やプロセス間でオブジェクトの値が変更されたとしても正常に動く、という驚異的な動きが可能なのです。

  1. A スレッドと B スレッドが動作している。
  2. 共有のオブジェクトを使っている。
  3. A スレッドが非同期に共有オブジェクトの値を nil にした。
  4. B スレッドはオブジェクトが nil であっても正常に動く。

という動きをします。

これを C++ のコードで書いてみると、

// 共有オブジェクト
static Com *com ;

void Athread()
{
	if ( com == NULL )
		return ;
	for ( int i=0; i<100; i++ ) {
		// 何かの処理
		com->method() ;
		...
	}
}
void Bthread()
{
	if ( com == NULL )
		return ;
	com->method() ;
	// 解放するとか
	com = NULL;
}

このような場合、A スレッドは、com->method で落ちてしまう可能性があります。なので、com を使う時にはいちいち NULL であるかどうかをチェックしないと駄目なのです。非同期処理の場合は、これが結構面倒で、C/C++ の場合はロックを掛けたりしますね。C# も似たような苦労があります。
この例では、一か所しかないのですが、複数の共有オブジェクト、複数のメソッドを呼び出すとこのチェックは結構手間です。

void Athread()
{
	if ( com == NULL )
		return ;
	for ( int i=0; i<100; i++ ) {
		// 何かの処理
		if ( com != NULL )
			com->method() ;
		...
	}
}

また、細かく云えば、if ( com != NULL ) と com->method() の間にインタラプト(割り込み)が発生する可能性もあるわけで、これを完全にガードする方法はロックしかありません。実際、OS 内部ではこの手の非同期処理をちまちまとアセンブラレベルでロックしているのですが、実は、Objective-C で書くとすんなり解決ができます。

// 共有オブジェクト
static Com *com ;

- (void)Athread
{
	for ( int i=0; i<100; i++ ) {
		// 何かの処理
		[com method];
		...
	}
}
- (void)Bthread
{
	[com method];
	// 解放するとか
	com = nil;
}

こんな風に、com ポインタが NULL であるかどうかを気にせずに書けます。これは、そもそもが com のポインタが nil である場合は method が呼び出されないという objective-c の仕組みにより有利な書き方ができるのです。
更に云えば、C/C++ ではロックを掛ける必要があった部分が、objective-c ではロックを掛ける必要はありません。おそらく、相当非同期に com ポインタが nil になったとしても正常に動くと思われます。

■まとめ…のようなもの

と、まぁ、こんなことを objective-c のコードを書きながら思ったわけですが、実のところはどうなんでしょうね? iOS の中身が objective-C とは思われないので、多少は違うのかもしれませんが、nil の挙動のおかげで非常にバグが少ないプログラムが書けるはずです(それでも、不具合があるのは Apple の C言語部分ではないかな、と想像したり)。

nil/NULL を指定しているのだから「アクセス例外」が発生して欲しい、という意見もあるでしょうが、実行時にはこういう「フェールセーフ」(安全系に倒れる仕組み)は重要かと思っています。人的ミス(コーディングミス)が発生しても、ほぼ安全にコードが動くという話はまた別の機会に。
↓のところに、ちょっとだけ書いてあります。

フェイルセーフなコードを書くには? | Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/2173

カテゴリー: C#, C++, Objective-C | 8件のコメント

[C++] そういえば auto の落とし穴を示しておくと

C++11 あたりから、つーか、VC++2008 でもあったような気がするのですが、C++ では C# の var のように auto が使えます。
VB.NET の dim が dim に変わったように、C++ の auto が auto に変わったわけですが、昔の auto を知らない方は、まあ、知らなくてもよいかと。事実上使わなかったし。

さて、C++ でも auto で型推論ができるようになった訳ですが、これにちょっと落とし穴があるってのを少し。
auto を何に使うかというと、最初は typedef の代わりですかね。よくやる std::vector<string>::iterator ってのを、var で書き直すと非常に楽になります。

vector<string> vec;
for ( vector<string>::iterator it=vec.begin(); it != vec.end(); ++it )
{
  ...
}

こんな風に横に長いコードが

vector<string> vec;
for ( auto it=vec.begin(); it != vec.end(); ++it )
{
  ...
}

という風に書けます。かつては、typedef をして

vector<string> vec;
typedef vector<string>::iterator VECTOR_IT:
</p>
<p>
for ( VECTOR_IT it=vec.begin(); it != vec.end(); ++it )
{
  ...
}

というコードもあったのですが、これで無駄な typedef が駆逐されます。この typedef って #ifdef ができないので、結構厄介なのです。

■型推論を推論する落とし穴

皆さまご存じの通り、C++ には、「値型」と「ポインタ」って区別があります。更に云えば、「参照」ってのがあります。

先の型推論「auto」を使うと、

vector<int> vec;
auto bar = vec;

としたときに、bar の中身は vec と同じになります。なので、一見、「参照」のように見えるので、

vector<int> vec;
vector<int> &bar = vec;

と思い気や、実は違います。vector<int> のコピーになり、vec と bar は別ものなのですよ。

#include <vector>
#include <iostream>
using namespace std;

int main()
{
	vector<int> vec;
	auto bar = vec;
	// 要素を追加する
	vec.push_back(1);
	cout << "vec:" << vec.size() << endl;
	cout << "bar:" << bar.size() << endl;
	return 0;
}

のコードを動かすと vec:1, bar:0 という値を得ます。

そこで「参照」であることを明確にして「&bar」のようにすると、

int main()
{
	vector<int> vec;
	auto &bar = vec;
	// 要素を追加する
	vec.push_back(1);
	cout << "vec:" << vec.size() << endl;
	cout << "bar:" << bar.size() << endl;
	return 0;
}

vec:1, bar:1 という値を得ます。

ちなみに、ポインタを推論させて 「&vec」と指定すると、うまく vec:1 bar:1 になります。

int main()
{
	vector<int> vec;
	auto bar = &vec;
	// 要素を追加する
	vec.push_back(1);
	cout << "vec:" << vec.size() << endl;
	cout << "bar:" << bar->size() << endl;
	return 0;
}

なので、C++ の auto による型推論は、bar と &bar と *bar をうまく使い分けないと駄目なんですよ。まあ、大抵の場合大丈夫なんですが、コピーコンストラクタが定義してある場合はコンパイルエラーにならないのではまりどころです。
ちなみに、C# の場合は、このような装飾子がないので、推論に任せるしかないって感じなんですけどね。暗黙の変換を利用すると、var と 型指定では違った値にするトリックもできるし、dynamic の場合は型が後から変換されるために更にややこしかったり。

カテゴリー: C++ | 4件のコメント

実践 UIDD 入門のツールを考える

かつて、MVCが華やかし頃、その昔にはDoc-Viewというのがあり、その前には UI はキャラクタインターフェースとコマンドの組み合わせ出来ていた。そして、今は「プロトタイプUI」を「ユーザビリティUI」と分離させて、いまや GUI は完全にユーザーのものになったのである。

…というのを妄想してプレゼン資料を書いてみるテスト。MDA(Model Driven Architecture) とは違ったアプローチの仕方ですね。

■プレゼン資料

 

■ちまちまと説明

User Interface Driven Development は、UI を中心にしてソフトウェアを構築しよう、という主旨があって「考え中」なのですが、 そのためには、UI と内部ロジックの分離は必須なのですよ。ユーザーとはいえ、ライブラリに対して言えばプログラマもユーザー、プログラマが作ったアプリケーションを使うユーザー、という相対的な面もあり、いわば「おもてなしの心」って奴です(とお茶を濁します)。

さて、VB2 の頃に出てきた一番の売り文句が「プロトタイプが簡単にできる」だったのですよ。当時、VC++ で UI を作るのは非常に大変で、方眼紙を使って Windows アプリの UI を顧客に説明するか、Excel でぽちぽちと作るぐらいしか方法がなかったのです。まぁ、簡単なものであれば Excel を使うのもよく、当時 Excel VBA を使ってユーザーがアプリケーションを作れる、という一大ブームもあったわけで(それで被害をこうむっている人も多いみたいですが)、そのあたりはかつての COBOL を彷彿とさせます。いやいや、皆様あまり歴史は得意ではないようです。
そんなわけで、VB2 を使って「プロトタイプ」というものを作るわけですが、ComboBox やら TreeView やらをまじめに作ると結構大変なのですね。しかも、「顧客に見せる」ということ中身のデータを「ほんもの」らしく揃えないといけないという「固定概念」もあって、プロトタイプのくせに時間がかかっていました。
そして、当時「時間がかかったプロトタイプ」をどうしたかというと、「もったいない」から実プログラムに使おうという「もったいない」号令が発せられたわけです。まあ、プロトタイプにせよ、時間がかかり人件費がかかりコストがかかっているわけですから、マネージャとしてはなるべく「流用」をして、実コーディングの時間を減らす=コストを減らすことをしたい訳ですよ。が、実際はどうだったかというと、プロトタイプはプロトタイプに過ぎず、中身を本格的なプログラムに切り替えるには、それ相応の労力が必要であり、一概にプロトタイプを流用したからといって工数が減るという訳ではなかったのです。むしろ、時間がかかったりします。このあたり「プロトタイプ」としての試作品と、実コーディングを効率化させる「テンプレート」技法との差がわかっていなかった(という人が多かった)ということになります。
さらに言えば、なまじ「プロトタイプ」がきれいに出来上がってしまうものだから、プログラム自体がよくわかっていらっしゃらない顧客様におかれましては、「これ動いているから、これでいいじゃん」とのたまう始末でして、いやいや、所詮、紙芝居にすぎないのですから中身は空っぽなのです。なので、これから作りこみをしなければいけないのですが、「もうできているから、工数を削っていいよね」という仰りようもありまして、「プロトタイプ」に関してはもうこりごりというプログラマの方もたくさんいるかと。

で、ひとつの解決案としては、プロトタイプであること、紙芝居であることをわかりやすくするために、ペーパープロトタイピングという手法を取ったり、Microsoft の提案する Flow ツールを使ったりするわけです。あと、Visio の画面作成ツールとか。

■変更コストについての考察

まあ、画面作成というもの、ユーザビリティテストというものは、ソフトウェアの開発工程において一番最期におかれることが多いのですが、結局のところそれは上記な理由から「プロトタイプ」の練り込み具合、と実コードの入れ込みの乖離が原因だったりします。作ってみないことには、本格手な UI のテストができない、という訳ですね。確かに、車の試作品を作ってコースを走らせて、乗り心地をチェックするという「ユーザビリティ」テストがあるわけですが、これって車の量産よりも前にあるわけで、全体の製造工程の最後にある訳ではありません。もちろん、ソフトウェア開発は通常の製造業(プロダクト)とは違い、一過性のプロジェクトであるので、ソフトウェア開発自体はすべて「設計」であるということお言えるのですが、にしても、わざわざ仕様変更にコストがかかる(人件費と時間の両方がかかる)プロジェクトの最後の工程にユーザビリティテストを置くのはどうかな?と以前より思っていたわけです。

解決方法としては、実は2つあります。

  • ユーザビリティテストでの変更が、無視できるぐらいコストが安い(時間が早い)場合
  • ユーザビリティテストを変更コストの安い、前の工程に戻す。

という2つの方法です。たとえば「無視できるくらいコストが安い」の方法としては、Visual Studio 上でコントロールの背景色を変える、ってのがあります。以前は、コードでちまちまやっていたのですが、最近はプロパティの値を変えるだけですから、おそろしく「コストが安く」なりました。なので、この手のカラーリングに関しては、最後の工程でも構わないのです。よく「仕様変更」の受け入れ判断の基準は、この「変更コスト」が重視されますよね。

そうすると問題は「変更コスト」の高いものです。大体の場合、お客に「諦めて」もらうわけですが、社内アプリならばともかく、パッケージ製品であったり、iPhone などで配布するアプリだったりすると、そのあたりの「ユーザビリティ」は販売数に影響することがあるので、慎重に考える必要がありますよね。場合によっては徹夜で直すという、プログラマの安いコストを使う手段を使うことが多いのです。

でも、ちょっと考え直すと、方法はいくつかあって

  • 変更コストが高いものを、安くする手法を取り入れる。
  • 変更コストが高いものが、販売数(機会損失)に直結するか検討する。

という風に、変更コストに対する対処もいくつかあるのです。機会損失のほうは、もう少し分割できて、Windows Update のように後からプログラムを更新できるようにするとか、リリース後に対処するという「時間コスト」を伴わない方法を取ることもできます。

しかし、このリリース後の変更コストなのですが、リリースした後にもプログラマの時間コストを消費するために、隠れた変更コストではあるのですよ。あまり言及されていませんが、たいていの Web サービスが、サービスをリリースしたあとの不具合対蹠に時間を取られてしまい、新規機能がうまくリリースできない、あるいはサービス自体が陳腐化してしまう、のはこのあたりに原因があります。

というわけで、頭を使って「変更コストが高い」というのを「変更コストが安い」にシフトさせましょうというんが、プロトタイプ UI と実 UI の分離の主旨です。

■プロトタイプ UI の分離

実は、MVC パターンをうまく活用すれば(MVC パターンの実装の活用ではなくて、デザインパターンのひとつとして、ってことです)、View の変更はかなり楽になります。私がよくやる手法として、

  1. プロジェクトの初期の段階では、チープな View を用意して業務ロジックをテスト
  2. 業務ロジック自体は、xUnit を使う。
  3. 画面操作に関しては、チープな View でテストする。
  4. チープな View を徐々に本番 View に変更していく。

という手順で View を作ります。これの良い点は、最初のチープな View を変更するコストが恐ろしく安いことです。画面を増やすのも楽だし、画面自体のバグに悩まされることも少ないのです。かつ、業務ロジックを xUnit でテスト済みとして動かすので、画面のバグと業務ロジックのバグがきれいに分離できます。

しかし、長くこの手法をとっているのですが、問題もあって、工程が進んでいき複雑な View となってしまったときに、業務ロジックの変更が容易ではなくなってしまうのです。本来ならば業務ロジックは View と分離されるべきなのですが、そこは実学としてのソフトウェア開発ですから、混ざってしまうこともしばしばです。その混ざったところでバグが発生すると、なかなか調べるのが大変ということになるのですよ。このあたりは、システム試験までソフトウェア工程を付き合っている方ならばわかると思います。

そこで、昔とっていた手法としては、チープ View を隠し View として残しておくことです。業務ロジックを確認するためのデバッグ UI という立ち位置ですね。複雑になりそうな画面は、途中からデバッグ用の UI を新たに作ったりします。
しかし、これもちょっと問題があって、業務ロジックにチープ View が追随しないことがあるということです。実際デバッグ用に動かしてみたら、画面ロジックが違ってしまっているために「動かない」ということで、デバッグにならない、という落ちになるのです。

そんな訳で、プロトタイプ UI を残す場合には、業務ロジックに追随する形で、プロトタイプ UI を改変する、という手間が必要となり、結局のところ手間=コスト面から、プロトタイプ UI を残さないという結論にならざるを得ないのです。

■高速開発としてのプロトタイプ UI と実 UI

そういう訳で、既存の構造で「プロトタイプ UI」を残すのは難しいという考えから、では、根本から MVC パターンを考え直したらどうなるのだろうか?と思考実験してみたのが先のプレゼンテーションです。MDA が大変なのは、手作業(コーディング量)が多いからです。オブジェクト指向をインターフェース経由で行おうとすると、インターフェース絡みは自動化しておかないと(あるいは言語拡張をしないと)ちまちまとしたコードが多くなります。またインターフェースを重視という思想自体が「神の視点」(この話は後日)という時間軸を無視した思想に基づいてるので、当初の思惑の範囲内でしかシステム構築をできないのです。

そんな訳で、いつでも「後戻り」が可能であるという前提に経って、プロトタイプ UI と実 UI の両方を使っていきます。プロトタイプ UI 自体は極力コストを掛けないというパターンを使って、Excel のグリッドに項目を作ります。実際は、Excel 風のプロトタイプ作成ツールを用意するわけです。

永続化となるデータベースとの O/R マッピング、Model の構成、画面の基本的な Validation、項目同士の結合は、あらかじめ機能として用意してしまいます。項目の追加や削除は、まずはプロトタイプ UI に対して追加削除を行った後に、実 UI に反映させます。プロトタイプ UI の操作、更新のコストを減らすことにより、二度手間のコストを減らす、という方法ですね。

これの発想自体は、Rails や WebMatrix にあるものですが、発想のもととしては CakePHP です。プログラムを動かしながら、画面を構築していくという発想は、他にはないものなので一見してみるとよいです。

CakePHP はマニュアル無しでサイトを作れるのか? | Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/1753

な訳で、これを妄想とするか、実装するかはちょっと思案中。Windows Metro か iPad で作るとよりベターかなと考えていますが、どうでしょう?

カテゴリー: UIDD | 1件のコメント

【募集】Revese Reference Book Series の執筆協力者を募集

計画段階ではありますが、ざっとこんな感じで「執筆協力者」を募集します。
「協力者」となっているのは、単著、共著という形ではなくて、印税やらなにやらを共有して、次の資金にしましょうってな具合なので「協力者」になります。
まあ、自動的に PP-Club メンバになって貰って(準会員かもしれないけど)、そこから収入を得て貰いましょうってな具合です。

近々、(必ず?)某逆引きの執筆はスタートする予定なので、VB, C# の 2012版は確実。C++/CX 版は、状況によりけり。
技術メルマガはほぼ決まり、電子書籍化は自動化ツールを作る予定、WordPress Book 版は作らないと駄目だろうという状態ですね。

興味のある方は、以下まで。「RRB 執筆協力希望」とタイトルを付けて送ってください。折り返し、開発者エントリーシートなどを送ります。

お問い合わせ | Moonmile Solutions Blog
http://www.moonmile.net/blog/contact

カテゴリー: 仕事 | 【募集】Revese Reference Book Series の執筆協力者を募集 はコメントを受け付けていません

くたばれ TDD 原理主義者

いや、どこに「TDD 原理主義者」が居る訳ではないのですが、仮想敵としての「TDD 原理主義者」です(笑)。

早速、仮想な「TDD 原理主義者」の主な言い分を列記すると。

  • 全てのプログラムは、テストコードから作成しなくてはいけないッ!!!
  • 変更が発生した場合は、テストコードを修正してからッ!!!
  • 全てのメソッドはテストコードを書くべきであるッ!!!
  • UI 部分もいずれは xUnit を使わないといけないッ!!!
  • 実コードとテストコードは同じ言語でなくてはいけないッ!!!

な言い分がある…としますね。ええ、仮想ですから。実はケントベック著「テスト駆動開発入門」をざっと読んだだけだと上記な「原理主義」的な発言をし始めます。中身は、Java で書いてあるのですが、これをひと通り自分の使っている言語でやっていくと上記のような発言が「原理主義」的な発言でしかないことが分かります。

という訳で、以下、私なりの論破を書いておきますね。

■全てのプログラムは、テストコードから作成しなくてはいけない?

まあ、原則としてはそういうほうがベターなのですが、最近のように IDE 全盛の時代になり、コーディングをするときにインテリセンス(補完機能)が付くとなると作り方は別ですよね。テストコードを作る時には、まだ母体(テスト対象のコード)が無い状態では、当然のことながらインテリセンスは効きません。コンパイルさえも難しいわけです。

なので、テスト駆動にもあるのですが、いちど母体のひな型を作ってからテストコードを書きます。

…ということになっていますが、もうちょっと先に進むと、テストコードで母体の使い方を模索した後に本体のコードを書くというのが、実はユーザーインターフェースとしては良いことが分かっています。というのは、テスト駆動を行う場合(あるいは xUnit を導入する場合)いきおい、テストコードを書くために、関数やクラス名を先に決定しようとしてしまいます。実際のコードは「書いてみないとよくわからない」という前提があるのに、クラス名や関数名やパラメータを先に決定しようとする矛盾があるわけです。なので、本来のアジャイル的な手法を TDD に導入するならば(実際は、アジャイル手法を支える手段が TDD なのですが)、

  1. クラス、関数の使い方をテストコード=実験コードを使って書く。
  2. ひとまず、コンパイルが通るまでの本体コードを書く。この時点では、Assert はいれない。
  3. いくつか繰り返して、利用できるコードができたら、Assert を入れる。
  4. 以下は TDD の手法で繰り返し/リファクタリングする。

という流れになります。1,2 の「模索」が抜けると、TDD なのに一気にウォーターフォール地獄に突入するので注意が必要です。

■変更が発生した場合は、テストコードを修正してから?

まあ、原理的にはそうなのですが、実際はどちらでもいいのですよ。と言うのも、ある程度きっちりとテストコードを書いていると、

  • 本体コードを修正することにより、他のコードでエラーが出る。

ことが多いのです。本来のテストコードではなくて「影響範囲」と呼ばれるコードの範囲がエラーになるのです。実は、作業量的にはこちらの「影響範囲」のエラーのほうが重要なのです。TDD を使う場合、通常はオブジェクト指向言語を使う訳で、それに従うと「隠蔽化」がうまくできていれば、この手の「影響範囲」は非常に少なくてすみます。場合によっては全くありません。ですが、いろいろな static 関数やもろもろの設定が入り混じっているとこの「影響範囲」が非常に大きくなります。

こういう場合には、そこに手を入れるのは「危険」だから、別の方法を模索せよッ!!! という信号をキャッチしているのですね。というわけで、いきなりコードを修正したほうが作業量的に良い場合があります。

■全てのメソッドはテストコードを書くべきである?

これは、ケントベック氏自身が最近言っているように、全てのメソッドに対して書く必要はありません。単純なget/setのプロパティや、間違いようのない単純な計算までをテストコードに入れるのは時間の無駄です。そういえば、Visual Studio 2010 ではテストコードの自動生成があったのですが、VS 2012 ではなくなっています。「自動生成」自体は、あまり良い機能とはいえませんが、先に言うように「ひな形」を作るのは適しています。この件に関しては、M$ が原理主義に陥ってしまったのかもしれません。

なので、private メソッドは普通テストコードを書きません…が、複雑な private メソッドの場合は必要ですよね。そういう場合は、適当にコンパイルスイッチを使って public にしてテストをするコードを作ったほうがベターです。リフレクションを模索する方法もありますが、public するだけならば、作業量としては楽ですからね。ええ、メモリの配置が違うので、バイナリ構成が違う、というパターンもあるのですが、それほどシビアではない場合はよいでしょう、ってことで。

■UI 部分もいずれは xUnit を使わないといけない?

ここ、私も10年前はそう思っていたのですが、TDD の本質といいますか作業効率を上げるというアジャイル的な指針に沿うならば、無駄なことはやめよってことですね。UI の場合は、マウスクリック、テキストの入力、ウィンドウの移動など様々な要素が絡み合っています。その「絡み合っている」部分、曖昧な部分を、xUnit という「きっちり」とした部分で対応させるのはどうかな?と思う訳です。なので最近は、UI 関係のテストは、手作業に徹するようにしています。それ以外のライブラリの部分を xUnit を使う訳です。

なので、この方法を取るためには、MVC パターンを使うか、それに似たパターンでロジックの部分で xUnit を使うという設計が必要になるのです。

かつて、ガラケーの開発をした時に、ガラケーアプリのテストはひたすら人間がやっていました。親指でぽちぽちとひたすら1日8時間テストを繰り返すわけです。ゲームのテストもそうですが、いやぁこれはちょっと…人間のやることではないな、と思ったものです。ええ、派遣さんがやるんですけどね。

スマートフォンの場合はどうなんでしょうかね?シミュレータがあるから多少マシになったかもしれませんが、テスターの苦労は大変なもので、ええ本音を言えば関わりたくありませんッ!!! ってな位だと思ってます。

なのでこれを避けるために取る方策としては、xUnit で UI テストを自動化するのではなく、

  • 設計の段階で、xUnit を使う部分を決めておく。
  • 設計の段階で、UI テストを行う人件費/作業量を算出しておく

ってことですね。そうすると、人的作業の費用対効果が分かるので、このインターフェースは避けたほうがいいぞ、ってことになります。

■実コードとテストコードは同じ言語でなくてはいけない

これ、昔から言われていたことで、Java のテストをするならば、Java で書く。C# のテストをするならば、C# で書く。というのが「原理」です。この原理の理由としては、自分のテストコードは自分で書く、自分でリファクタリングをする、というパターンがあるからなんですよ。他の言語を使うと、頭を切り替えないといけないので、コーディング→修正のサイクルが遅くなってしまうという訳です。また、先の UIDD の理念から、テストコード=ライブラリの利用方法になるので、同じコードが望ましいわけですね。

が、なにも「同じでなくちゃダメ」って訳でもありません。ストアドプロシージャのテストをするのに、SQL 文を駆使しなくてもよいし、Fortran のテストをするのに、Fortran 自身で書く必要もありません。

  • 効率的にコンピュータを動かす言語(SQL や Fortran など)
  • テストを効率的に書きやすい言語

とは別であっても良いのです。

ちなみに、いくつか xUnit の「方言」がありますが、どれを使っても一緒です。と言いますか、長く使えるライブラリを使うのが無難ですね。私の場合、未だに古い CppUnit を使ってテストコードを書きます。実コードのほうは色々と新技術を使ってもいいのですが、xUnit の場合は古臭いパターンを使って、Assert を書くほうがよいのです。と言うのも、テストコード自体を書くのに頭を使いたい訳ではないですよね?本コードを作るのに頭と時間を割きたいのです。って理由が第一です。

 

さて、ここまで書いて「立ち上がれ TDD 原理主義者」というのも考えたのだけど、やめておきましょう。多分、いつまで経っても立ち上がらないし。

カテゴリー: 開発 | くたばれ TDD 原理主義者 はコメントを受け付けていません