MVP Global Summit 2014 感想戦

MVP Global Summit
http://mvp.microsoft.com/summit

MVP 自体は 4年目なのですが、Global Summit に行くのは初めて。さっくりとツアーで行ってツアーで帰ってくるつもりだったのですが、同室の方の都合で最終日まで Red Lion に1日伸ばしでした。セッションの会場はマイクロソフト社内なので、ホテルからバスで送迎だし市内から遠くてもあまり変わらんですよね、安いし(ツインで120$ だったので、延長分はひとり頭 60$ でした)。

初日のベイエリアの観光以外は最終日の午後にベルビュースクエアを回ったぐらいで、碌な観光もせずに勉強会のノリで行ってきました。ぎっちり、3日間ひとりでセッションを回ってきたのでほぼ英語漬けの毎日ですが、なんか、あのスピードの英語ヒアリングはつらいです。スライドとかデモをやっているときはいいんだけど、ディスカッションになって(スライドの途中でも容赦なく質問をして、容赦なくディスカッションになってしまうあたり欧米風なのか、やっぱり言いたい MVP さんがたくさんやってきているのか)しまうとかなり辛い感じ。GAG のところが笑えないのは、今後ヒアリングを第一に勉強しようという原動力にはなるかもって感じです。やっていることは、所詮コンピュータ関係なので、概要は聞き取れるし、込み入って難しい話になればこれは英語でも日本語でも難しい話になってしまうので、同じことです。セッション中に手を上げて、スライドの途中でも止めてしまうスタイルは、.NETラボで発表するときにでも取り入れていきたいですね。スライドを淡々と読み上げると眠くなってしまうので、デモを交えてという工夫をやるのですが、質疑応答…というか議論自体が間に挟んでしまえばスライド自体ほとんど要らないという利点もあります。あと、顔を合わせている「勉強会」なりのメリットもあるでしょう。

F# のランチセッションで、替え歌に合わせて OWIN を解説するってことをやっていました。以前、プロ生で西山さんがギターの弾き語りセッションをやっていましたが、ああいうノリもありかなと思ってます。日本の勉強会だと世代差が気になる感じだけど、グロサミに出て手を上げているガリガリ質問しているのは50歳以上っぽい人(私よりちょっと上ぐらい)だし、そういうかき回し方もよいでしょう。

私が主に行ったのは、IoT のセッションです。Visual C# ってところで、ASP.NET vNext と Roslyn 、Xamarin はちらっと回ってきて、後は IoT に入り浸っていました。セキュリティ F# セッションってことで、てくてくと雨の中を歩いて聞いてきましたが(10人ぐらいいて、部外者が2人な感じだったよw)、ほとんどは Embedded のところです。Microsoft Band のページを調べていて、話しかけてきたおじさんに(自分もおじさんですが)、Raspberry Pi やってて、これから Spilder で勉強するつもりなんや、って話すと、Splider でバーベキューの温度を測る機械を作っている(らしい)ページを見せてみせてもらいました。あと、なんか前のほうで、Not NDA のページをセッション資料を作っている人がいるなーと思ったら、最後の LT(10分ぐらいのミニトークで、MVP が発表する)で、組み込み機器は「Wife のように扱えるといい」(英語を忘れました)という、ヒーターとかオートロックとかをまとめて Windows Phone のアプリにしたりしている人でした。「Wife のように~」のところで、皆が爆笑しているのであれは流行り(独身が多い?)なのかも。組み込みの場合は、年齢層が高.くて、Windows CE、Windows Mobile から、Windows XP Embedded な人が多いですね。完全に組み込みな、.NET Micro Framework のときは質疑応答が少なかったので、少しジャンルが分けられているようです。

codenameathens

Microsoft’s fitness band: What kinds of software and services are inside? | ZDNet
http://www.zdnet.com/microsofts-fitness-band-what-kinds-of-software-and-services-are-inside-7000035344/

Windows 10 に統合して、4つの分野に Framework を分ける、っていう話は、Tech Ed Europe で発表されているもので、NDA ではありません、よね。Windows Phone や 従来の Surface RT のような Windows RT は Windows 10 “Mobile” になって、従来の .NET Compact Framework は、Windows 10 “Athens” になるってことです。更にコンパクトになっている組み込みに使う .NET Micro framework は通りに使われる感じです。Microsoft Band の UI は、Windows 8.1 のスタート画面風なので、Embedded 8.1 か Windows Phone ベースなのかなと思っていたのですが、スライドを見るとそれっぽい時計の絵が描かれているので、ひょっとすると .NET Micro かもしれません。.NET Micro は情報だけはちららと追っていたのですが、今年の夏にやっとこさ Splider を買ったぐらいで、netduino の存在は知らなかったんですよね。

2010年頃にすでに発表があって、日本で買えたりしてました。「してました」って過去系になっているのは、スイッチサイエンス社が在庫切れになったままで、新しい netduino plus 2 を扱っていません。コネクタ等が arduino 互換なので、外部機器を共用するならば netdouino のほうがいいかなと思っています。まあ、コードの接続がややこしいですが、ハルロックを読んで頑張りましょう(ちなみに、ハルロックには基板解説とかは出てこないので、やる気だけを貰うということで)。

日本の IoT と海外の IoT の違い

Microsoft 技術からの視点なので、本格的に Raspberry Pi とか Aruduino から見たら(半田付けする、という点で)違うかもしれませんが、グロサミに行った感じでは、日本と海外(欧米)とでは結構違いがあります。

私は Kinect や Leap Motion を扱わないので(あと Oculus Rift DK2も)そのあたりはよくわからなくて、日本の組み込み系は MS太田さんオンリーなのかなと思っていたりするわけですが、Raspberry Pi や Aruduino で何かモノを動かそうと思うと、もうちょっと周辺の器械を活用しないと駄目ですよね。さきほどの MVP ライトニングトークスで出てきた、デカいモーターや、ごついドライヤー(温度センサーを温めるらしい)、デカいタッチディスプレイを担いでくるあたりが、海外の IoT さんの面白いところです。

確かに、Windows Phone を買ったり、Surface Pro を買ったりするのもいいんですけど、同じ値段ならば、Rspberry Pi を買ったり、Aruduino 用のセンサーを買ったりするほうが、「よりたくさんの機器が買えるんですよッ!!!」。まあ、センサーにも色々あって結構な値段はするし、Lego Mindstorms EV3 は Windows Phone と同じぐらいの値段になるので、どっちを買っても一緒ではあるのですが(苦笑)。

そんな訳で、日本の IoT は、Internet のほう(Windows Phone とか Surface とか)から入っている感じがしますが、欧米の IoT は、Thing のほうから入って来てます。周辺機器の豊富さもあるのかもしれませんが、もともとある DYI の精神なのかな、と思ってます。家のガレージに工具を置くことあができたり、広い公園でラジコンやロケットを飛ばしたりするのが普通の環境じゃないと、あの発想はできないのでは?ってな感じです。

じゃあ日本はどうやって IoT というジャンルを確立していくのか?というと、同じ方面じゃなくてもよくて、ロボットでも踊りでもARでもVRでもよいのですが、もうちょっと海外と対抗するような視点を持ってモノを作ってもよいかなと思いました。Oculus も初音ミクもMMDもすごいといえばすごし、そこそこ手軽に実現ができるようになってるし、日本でやっている人が多いから日本語で情報が得られるので、初手としていいのはいいのでしょうが、そのまま海外(欧米)に持っていくと違和感アリな感じです。それを日本独自の文化と捉えるか、違和感のまま捉えるか、ってのがあると思います。勿論、日本のアニメ文化の延長上でという感覚もあるんですが。

そんなこんなで、自分としては今まで通りニッチなところかつ、海外で受け入れやすいスタイルで、Raspberry Pi を扱っていきます。いつかの IoT のセッションを見ていくと、海外(欧米)が特に進んでいるという訳でもないし(同時に日本が取り残されている訳でもないし)、いくつかの面では高速道路も準備されて、マス的な Microsoft Band のような当たりを日本で作るのは難しいでしょうが、もっとバリエーション(機器の組み合わせてという意味で)を作って、それを実現するときに、.NET Framework + Xamarin + Raspberry Pi/Netduino  + AllJoyn のようなスタイル確立できるかな、と思って帰ってきました。ひとまず、.NET Micro framework が動く netduino を試してみるのが初手、つーか、その前に FEZ Spider Starter Kit ぐらいは開封せねば。

英語のヒアリング

ディスカッションをするには、英会話が必須なんですが、TOICE 300点前後(程度だよ。たぶん。10年前ぐらいだけど)の自分としてはヒアリングをやらないといかんと痛感です。たまに channel 9 とか TechEd の画像を流しっぱなしにして仕事をしていますが、スライドとは関係ないところで話をしていると途端に分からなくなります(キーワードを拾い集めて、おおまかな意味から推測するってことをやっているので)。コンピュータの本は洋書が多いし、MSDN で英語文にあたることが多いから、英文をざっと読み込むことはできるし、英文を書くときは Google 翻訳を使ってほぼコピペで流すことはできるのですが、カンファレンスのヒアリングは難しいですね。自分の後ろの席で、自動翻訳っぽい音が聞こえた(英語じゃない言語で、ちょっと遅れで話している感じ)ので、そんなのを使うのもアリなんでしょうが、やっぱり、英語は英語のまま理解するほうが脳への負担は少ないと思われます(疲れにくい、退屈して眠りにくいっていう意味で)。

レッドドワーフ号のイギリス英語のほうが少しわかりやすいけど、アメリカ英語と聞き取りづらいのはなまりの問題もあるかなーと思うけど、まあ、すべてとは言わなくても半分ぐらいは英語のまま理解したいですよね。お金を払って英語のセッションに行って、英語が聞き取れなかったら意味がないわけで(グロサミ自体は MS が会場費を持ってくれているけど、日本からの旅費は自前だし)、これは早急にやり始めないとという感じでした。

因みに、日常的な英会話も不便な私ですが、相手に話すときは「文法通りに話す」と意味が伝わりやすいです。文法通りってのは前置詞あれこれってのもあるのでしょうが、SVO を守って、3単語ずつしゃべればだいたい通じます。どう聞こえているか分からんけど、相手にとっては外人だから許してくれるでしょう。…つーか、経験上、意図を正確に伝えたいときは文法通りに、雰囲気を伝えたいときはジェスチャーでって感じ。ビジネスのときは困るだろうけど、街中歩くときと、同じプログラマの人と話すときはこれで十分かと。

カテゴリー: 開発 | MVP Global Summit 2014 感想戦 はコメントを受け付けていません

XAML とは何か? … Microsoft だけのものじゃない

XAML を勉強しておけば将来役に立つよ…と Microsoft 様よりお達しがあって久しいのですが、そもそも、XAML ってのは何?ってのが昨日気になって調べていました。データの形式だけで見れば、XML 形式なのですが、あえて「XAML」とするところに意味はあるのか?かつ、Xamarin.Forms で使われている XAML は XAML と言えるのか?って話です。

Japan Xamarin User Group (JXUG)
https://www.facebook.com/groups/xm.jxug/
Using Workflow Markup
http://msdn.microsoft.com/en-us/library/vstudio/ms735921(v=vs.90).aspx

榎本さんの話で、Xamarin.Forms 以外にも WF(Workflow)でも使われているそうです。中身を見ると、XML でも良いような気がするけど、なぜに XAML なのか?

XAML は仕様が公開されている

結論から言えば、XAML の仕様は公開されています。Microsoft 自身が MS-XAML として公開していて、それに基づいて WPF やストアアプリの XAML を作っています。当然、WF の XAML も作っていて、同じように Xamarin.Forms の XAML もこれに基づいている(ハズ)です。

XAML 構文の詳細
http://msdn.microsoft.com/ja-jp/library/ms788723(v=vs.110).aspx

の中にある MS-XAML をクリックすると、公開しようの PDF に至ります。Silverlight などの XAML は以下でも公開されています。

Microsoft Domain-Specific Languages
http://msdn.microsoft.com/en-us/library/dd361847.aspx

ついでに言うと、Excel のファイルを保存したときにできる .xlsx の形式とか、VBA の仕様とかも公開されています。Microsoft は、この公開情報に基づいてデータを作っている(あるいは拡張している)ので、まあ、Office データの互換フォーマット率なんかは、このあたりを元にすれば適切かなーと思ったり。

XML と XAML の違い

SPEC をざっと読むと、いくつかの違いがあります。XAML ⊂ XML な訳だから、XML の形式に基づいてはいますが、いつかの拡張があるってことです。

  • namespace で http://schemas.microsoft.com/winfx/2006/xaml が必須
  • x:Class で実クラスにマッピングする
  • tagName.propName のように、ドットでつながった名前が特別扱い
  • attrName=”{Binding xxxx}” のような、属性値に {…} を指定したときに特別扱い

他にもいくつか細かい違いがあるのですが(「Name と x:Name を同時に定義してちゃいけない」という仕様がある!)、まあこんな感じです。

WPF やストアアプリ、Windows Phone で規定されているコントロールとかは XAML 本体とは別ものなので、Xamarin.Forms の XAML の共通部分も、ここの MS-XAML にあっている(はず)です。

名前空間 http://schemas.microsoft.com/winfx/2006/xaml を利用

XAML では x:Name のように、x 付きの属性が頻発するのですが、これが XAML の肝っぽいですね。名前空間のエイリアスが「x:」でつけられているのですが、「xxx:」のように変更することも可能です。

乱暴なことを言えば、このスキームを設定するだけで、XAML です、と言い張ることもできる…かもしれません。あまり意味はありませんが。

x:Class で実クラスにマッピングする

XAML は、XAML ファイル単体で存在するとは少なくて、特定のクラスとマッピングされます。XAML 内にある x:Name を x:Class で指定したクラスのフィールド(プロパティでも良い?)やイベントにバインドしています。なので、特にバインドしない場合は、x:Class を書かなくても良いと思うのですが。このバインド自体が、*.g.cs のようなバックグラウンドのコードを吐くので、ビルド環境依存になるような気がするんですけどね。このために Visual Studio で普通の C#/VB の XAML を書いたときにはバインド用の中間ファイルが作られます。F# の場合は、この中間ファイルを作らない(作れない?)ので、x:Class を指定せずにタイププロバイダを使うという方法を取っています。

ちなみ、自前の XamarinForms のプレビューアは x:Class を指定しているけど、動的にクラスをバインドするという手法を取っていて、動的なコードを作りません。なので、XAML 解析コードを自前で作れば、ちょっと違ったマッピングの仕方もできるということです。

ドットでつながった名前を特別扱いする

XAML を調べていた理由として、このドット付きの名前があります。<TextBlock Text=”…” Grid.Row=”0″ のように、親の Grid に設定をしたり、<TextBlock.Background>Black</TextBlock.Background> のようにプロパティを設定したりできます。ドット記号自体は名前に使ってよいことは調べたのですが、このドットの前後を SPEC で規定しているのか否か?ってところです。

MS-XAML を見ると、6.5.1. DottedXamlName として、ドット付き名前が規定されています。これに基づいて、ドット前後の XamlName に分けて XAML 解析を行うという訳です。

属性値に {…} を使う

XAML の拡張として、属性値に {…} が使われているのですが、これはどういうフォーマットなのか?自由フォーマットなのか?と思っていましたが、これも MS-XAML で規定されています。

6.6.7.1. Markup Extension Parsing なところで、MarkupExtension としてフォーマットが決まっています。なので、Text=”{Binding text}” のような感じなのも勝手なフォーマットを使っている、という訳ではないのです。

XAML 形式を解析する

Xaml ファイルをロードしてマッピングする場合は、XamlReader を使います。ストアアプリのような WinRT の場合は、いかな感じで読み込みます。

[WinRT] XElement を使い XAML を構築して動的に XamlReader.Load で読み込む技 | Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/6556

WinRT の場合、Windows.UI.Xaml.Markup 名前空間にあるのですが、WPF のような本来(?)の XAML は、System.Xaml の下にあります。何故、System.Xaml から動いてしまったのか、Xamarin.Forms に System.Xaml が無いのはなぜなのか、は分かりませんが、処々の事情がありそうです。

  • XamlXmlReader
  • XamlObjectReader
  • XamlServices

XAML 解析とマッピング自体は上記の 3つのクラスを使えばよさそうです。Read メソッドで SAX 風にタグを読み込んでマッピング部分を自前で書いていけばよいのです。Xamarin.Forms プレビュアは、XML として読み込んだ後に、独自に解析をしているので、このあたりを変えたいな…とは思ってはみたものの、Xamarin.Form には、というか mono には System.Xaml がないんですよね…ともったらあるよ( http://www.mono-project.com/archived/systemxamlhacking/ )。ストアアプリ WinRT のほうにも System.Xaml がないので、互換ライブラリを作って PCL 化するのがいいんですかね。

ここまで書いて、一切 UI な部分が出てきませんが、そうなんです。XAML は UI とは全く関係ないんですね。ってことは、普通にクラスにマッピングする XML 形式のデータであればよいのです。なるほど。

連載:Windowsストア・アプリ開発入門:第5回 データを画面に表示する (1/5) – @IT
http://www.atmarkit.co.jp/ait/articles/1311/01/news095.html

のように、デザイン時のデータ形式は、JSON と XAML が選べます。そうなんです。XML じゃなくて XAML なんですよ。これは、まあ、そういう意味があるということです(逆に言えば、クラス構造を外して、JSON のように XML 形式でも十分ではないか?とも言えますが)。

カテゴリー: XAML | XAML とは何か? … Microsoft だけのものじゃない はコメントを受け付けていません

TDD cannot Die. TDD は死ねません。

【翻訳】テスト駆動開発(TDD)はもう終わっているのか?PART I | POSTD
http://postd.cc/is-tdd-dead-part1/
【翻訳】テスト駆動開発(TDD)はもう終わっているのか?PART II | POSTD
http://postd.cc/is-tdd-dead-part-2/
2014-10-27 – やっとむでぽん – TDDの経験と現状のアンケート
http://d.hatena.ne.jp/yach/20141027

アンケート自体は「TDDに関心がある人」のフィルターが掛かっているので、数値そのものは意味がないのですが、傾向がわかります。私の場合、JUnit が出た当時から使っているので(その頃は CppUnit でテストしてた)かれこれ10年ぐらいやってます。最初のテストフレームワークは、自前の Excel VBA で C++ の自動テストをする、という自作 xUnit もどきを作っていて、その直後、Ruby の UnitTest から入ったぐらいですから、かなり初期の頃の TDD から入っています。XP のプラクティスのひとつとして、テストフレームワークと自動テストは必須だったので、それを最初に取り入れます。あらゆるテストを xUnit でやろうとした頃もあるのですが、UI 系のテストは諦めることにしています。というのも、「作業量に見合わない」作業をやっても仕方がないですから、の結論に至ります。

自前のライブラリを作るときや仕事でも TDD を使います。いや正確にはテストファーストではないのですが、大抵はテストコードを書いてから、それに合わせるようにライブラリを作ります。このあたりは、自前の UIDD (ユーザインターフェース駆動開発)のひとつで「見た目使いやすいものが、後後になっても使いやすい」に基づいています。

さて、そんな中で記事のタイトル通り「TDD は死ねません」≒ 死ぬことができませんな話を書き下しておきましょう。

何のために TDD を使うのか?

「プログラマの精神の安定のため」ではあるのですが、仕事なので「作業量」を少なくするため、という目標を掲げます。トータルの作業量が増えてしまえば(保守やリリース直前の不具合対応も含めて)、テストをやっていても自己満足にしかなりません。ちまちま一行プロパティをテストするのも「単体テストの行数を稼ぐ」という目的は達せられるでしょうが、最終的な目標は達成できません。どうやったってテストに合格するテストコードは書いても意味がないんですよ。なので書きません。

テストコードが複雑怪奇になって、テストコードの保守が大変になって、オブジェクト指向もどきのクラスライブラリが氾濫して自動テストをやるたびに、テストコードをあれこれと変えてやらなければ進まないのであれば、ざっくりとテストコードは捨ててしまいましょう。最終的な工程になって、手作業で UI を操作しなければうまくテストができなければ、自動テストをちまちまメンテするのは止めましょう。もっと、やらないといけないことがあるでしょう?ってな話です。

いわゆる、xUnit 的なツールは「治具」です。最終的な製品には含まれないけど、製品を精度よく作る、効率よく品質を上げるための「使い捨てのツール」です。なので、プロジェクトの横断するような自動テストを妄想するよりも、プロジェクトに密着したテストツールを、プロジェクト単位で作るほうがベータです。所詮「治具」なのです。だから、プロジェクトに密着したときにはじめて効果があるし、逆に言えば、他で便利だからといって自分のプロジェクトで便利とは限らない。そういう場合は、捨ててしまうし、そういう意味では、TDD is dead. なプロジェクトもあってもおかしくないのです。

そんな訳で、効率よく製品を仕上げるために TDD を使う、ってのがひとつの到達点です。適用範囲があるってことですよ。

何故 TDD は死ねないのか?

簡単です。TDD で作ったテストツールは、製品/成果物を裏で支えている訳ですから、製品が生きている間、それに密着したテストツールは生き続けます。と同時に、製品が死ねば、テストツールも死ぬ訳です。

製品やライブラリに何か新しい機能を付け加えるとしましょう。それが、テストコードにかなうものなのか、テストコード自体を破壊してしまうものなのか、という問題があります。テストコードは、適用範囲が決まっている(修正以前の製品に対して、の責務しかない)ので、新しく追加した機能に対して、テストコードの振る舞いは未知数です。いや、正確に言えば、機能追加について、2つの方法が取れます。

  • テストコードを破壊するような、機能を製品に追加する。
  • テストコードに適うような、機能を追加する。

後者のテストコードに適うような機能追加は、比較的簡単です。また、こうすることが TDD を利用する最大のメリットでもあります。既存のクラスやライブラリを壊さないように「再利用できる」ように機能を追加してきます。なので、既存のクラスやメソッドの振る舞いを変えないように注意深く作っていきます。この方法は、土台を固めて上に付け加えるように作っていく方法なのですが、デメリットもあります。複雑な内容に複雑な内容を追加していくために、最終的に複雑すぎるものができあがってしまいます。初期設計が悪いと、べたべたと回避するコードやメソッドばかりがちりばめられてえらいことになります。

そんな訳で、私たちは TDD is dead. と叫んで、テストコードを捨てます。以前のテストは設計思想が古いので、すべてを捨ててテストコードを書き直さないといけなくなります。クラスの設計をちょいちょいと直したいのに、膨大なテストコードを時間をかけて直すなんてナンセンスです。

でも、ちょっと待ってください。以前のテストコードを捨て去っても、また新しいテストコードを書くこともできますよね。所詮「治具」なのですが、新しい設計のクラスに見合ったテストコードを書けばいいだけです。つまりは、テストコードは、設計が死ぬとテストコードも死ぬのです。逆に言えば、設計が生きている限りは、テストコードは生きています。

テストコードを減らす努力をする

ちょっと考えてみましょう。TDD is dead. と叫んで、テストコードを投げ出したくなる理由は何でしょうか? テストそのものが嫌い? TDD 自体が嫌い? それはそれでよいのです、テストが嫌いならば、テストの無い形で MDA スタイルで作ることも可能です(それはまだ、夢物語な時代ではありますが)。テスト自体をやめてしまう、という方法もあります。しかし、逃れられないテストであるならば、何かと省力化する、あるいは効果の高い方法を取るほうがよいのではないでしょうか?

効率的なテストコードは、パレートの法則よろしく、全機能の 20% にだけテストコードを書きます。微々たる些末なコードにまでちまちまとテストコードを割り当てておくには、プログラマの人生は短すぎます。ランダムテストで自動化するとか、コードレビューで回避できるものも多いでしょう。なので、ユーザーインターフェース(クラスやライブラリを使う側の視点)でテストコードを書いていきます。

使う側の視点でテストコードを書くと2つのメリットがあります。

  • 利用しにくいメソッドやクラスを排除できる。
  • ヘルプ/サンプルとして利用できる。

既存のクラスライブラリを使うときに、あれこれと前提の設定があって、こっちのメソッドを先に呼ばないと次のメソッドを呼び出せないとか、メソッドの順番に依存しているクラスとかがありますよね。TDD のテストコード自体、オブジェクト指向設計に基づいているので、クラス同時は疎結合でないとうまくテストができません。複雑に絡み合ったクラスや機能の場合、長い手順を踏まないと呼び出せない UI みたいなものを自動化するのは大変な努力が要ります(もちろん、その努力に見合う、対費用効果があれば取り入れるでしょう)。そういう心理的な効果、行動経済学な考えからして、使いづらいライブラリを使いづらいまま作るのは、利用者のデメリットなんですよ。Microsoft のドックフードシステムってのもありますが、それのテストコード版です(にしても、.NET Framework で多々使いづらいクラス設計があるのは内緒です)。まずは、利用者の視点になってクラスを作ってみましょう。色々なパターンもあるでしょうが、あれこれとクラスを組み合わせ作る悪癖はやめましょう。それは、効率的なテストコードを作れなくする第一歩です。

利用者視点から作られたクラスは、そのままヘルプになります。テストコードがあれば、大抵のサンプルコードが要らないんですよ。逆に言えば、サンプルコードが簡単にかけなければ、テストコードも書けません。それほど複雑なもの(外部要因とか接続タイミングなどがあって、簡単にテストコードが書けないものは多々あります)の場合は、TDD に向きません。ちまちまとテストをしてください。また、テストコード自体をユースケースとして作ることも可能です。うまくクラス設計をやれば、UI なしでユースケースをテストコード内に埋め込むことができます。当然、うまくないクラス設計の場合は、複雑怪奇になって破たんします。クラス設計のリトマス試験紙にもなるのです。

複雑なモックアップを作らないと動かないテストコード自体も、避けるのがベターです。私自身もいろいろなプロジェクト単位で色々なモックアップを作ってきましたが、結局のところ、本番の DB 構造を使ったほうが便利だったり、試験環境を作ってガンガン廻したりするするほうが、複雑怪奇なモックアップを作るよりも作業効率がよいです。目標は「製品を品質よくしあげること」なのですから、まずはそれを第一に考えます。

そんな訳で、テストコードがガンガン減ります。以前は、「元コードの3倍ぐらいないと、テストの品質は保てない」と公言していましたが、訂正します。テストコードは1行だけでも ok です。ユーザー視点のテストコードが少しだけあれば、それに合わせるようにプログラムを品質よく上げる環境が、現在では揃っています。インテリセンスを効かせたり、自動生成コードを使ったり、手作業の部分を減らしていけば確実にテストコードも少なく済みます。

最初にテストコードを書く

自前の ExDoc ライブラリには実にチープなテストコードしかついていません。実は、元ネタは 2年ぐらい前に作って、最近ふたたび機能を追加し始めました。巷の OSS なコードには大量なテストコードがあるのが普通なのですが、私の場合は面倒…じゃなくて作業効率を考えて少しだけのテストコードを書いています。

public void TestLoad()
{
    var xml = &quot;<root><person name='tomoaki'>masuda</person></root>&quot;;

    var doc = ExDocument.LoadXml(xml);
    Assert.AreEqual(&quot;root&quot;, doc.Root.Name);
    // seek element
    ExElement el = doc * &quot;person&quot;;
    Assert.AreEqual(&quot;person&quot;, el.Name );
    Assert.AreEqual(&quot;masuda&quot;, el.Value);
    string val = el % &quot;name&quot;;
    Assert.AreEqual(&quot;tomoaki&quot;, val);
}

このテストコードを満たすように、ライブラリを作っていきます。結局、何をやりたいのかを先に決めておかないと、あれこれと無駄なクラスやメソッドばかりが増えていきます。このあたりは TOC(制約理論)の精神で、目標を決めて行動範囲を明確にする、っていう枠組みです。これが動作するためのコード自体はあれこと1000行弱ぐらいあるのですが、それぞれのテストコードは書いていません。必要があればちまちまと書いてもいいのですが、自己満足にしかならないので書きません。

逆に言えば、このひとつのテストコードが ExDoc というライブラリの動作を決定しています。それ以上でも以下でもありません。このテストコードを破壊するようなコードは ExDoc にもありませんし、破壊するようなコードを追加するときにはテストコードも死に、ExDoc の本体も死にます。それは別のクラスライブラリとして再出発したほうがいいですよね。

そんな訳で、オブジェクト指向設計をしている限りは TDD は有効だし、MDA のような別の手段が出てくるまでは TDD のほうが効率的です。勿論、WEB サイトを作るような時には不便だし、そこには踏み込めません。だって、WEB サイト自体はオブジェクト指向設計ではないのですから、もっと別なアプローチが必要でしょう? アプローチとしては、MVVM とか MVC とかテストしやすいように設計を組み立てることが必須です。テストしにくいものを無理矢理 TDD する必要はないし、TDD しても効果が上がらなそうなものに対してテストコードを大量に書くには、プログラマの人生は短すぎますからッ!!!

カテゴリー: 雑談 | 2件のコメント

ヒアドキュメントっぽく Yaml を書くための ExDoc.Yaml をリリース

Yaml を利用して C# でヒアドキュメントを考える | Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/6560

これの実装編です。Yaml をパースするためのライブラリが SharpYaml にあるので、これを使います。最初は、YamlDotNet を利用して作っていたのですが、 PCL 版がないので SharpYaml を使っています。SharpYaml 自体が YamlDotNet の派生ということなので、中身は同じクラスが使われています。

github

moonmile/ExDoc
https://github.com/moonmile/ExDoc

コードは github で公開していて ExDoc の下にあります。ついでに、HTML と Json 版も作りました。

  • ExDoc.Html – HTML から XML へ
  • ExDoc.Yaml – Yaml から XML へ
  • ExDoc.Json – Json から XML へ

拡張メソッドを使って、XDocument を生成します。そのまま XDocument で LINQ しても良いし、ExDoc に読み込ませて検索してもよい、というスタイルです。ExDoc 自体は XElement に依存しているので、検索結果を XElmenet に戻すことも可能です。まだ実装してはいませんが、そのうち属性や要素の値を変更して出力するようにもしていきます。

NuGet

nuget は、それぞれのアセンブリを別々に用意しています。

Moonile.ExDoc
https://www.nuget.org/packages/Moonmile.ExDoc/
Moonmile.ExDoc.Html
https://www.nuget.org/packages/Moonmile.ExDoc.Html/
Moonmile.ExDoc.Yaml
https://www.nuget.org/packages/Moonmile.ExDoc.Yaml/
Moonmile.ExDoc.Json
https://www.nuget.org/packages/Moonmile.ExDoc.Json/

もともと、Yaml や Json は XML にコンバートするメソッドを持っているのですが、いまひとつ使いづらい XML を吐き出すので、コンバートライブラリはそれを補足する感じです。設定やヒアドキュメントは人間に書きやすく、内部処理するときは XML 形式にしてプログラミングでやり易く、という主旨ですね。

ExDoc.Yaml の使い方

[TestMethod]
public void demo1()
{
    var yaml = @"
app:
- user: masuda
- apikey:  key-xxxx
- apipass: password
";

    var ys = new YamlStream();
    ys.Load(new StringReader(yaml));
    var xdoc = ys.Documents[0].ToXDocument();
    var doc = ExDocument.Load(xdoc);

    string apikey = doc * "apikey";
    string apipass = doc * "apipass";

    Debug.WriteLine("key:{0} pass:{1}",
        apikey, apipass);
}

たとえば、こんな感じで、yaml をヒアドキュメントで定義しておきます。このぐらいだったら、フィールドを使った方がいいし、そもそもアプリケーション設定を使えってのもあるでしょうが、まあ、テストの時とかちょっとした設定を書いておくときに便利でしょう。Yaml 自体はファイルから読み込みもできるので、外だしにしておくこともできます。

YamlDotNet/SharpYaml で作成したオブジェクトを直接参照してもよいのですが、KeyValue の羅列があったり、階層構造が面倒だったりして解析部分が結構面倒です。そういう場合は、クラスにマッピングするのがよいのですが、Yaml 自体の構造と同じでないといけないのが面倒です。
そのあたりを、なんかいい感じに ExDoc を使って検索します。

上記のコードを動かすと以下のような結果が取れます。

key:key-xxxx pass:password

このあたりの暗黙のキャストと要素名の使い方は、調べてみると Json.NET でも似たものがありました。

Json.NET – Modifying JSON
http://james.newtonking.com/json/help/?topic=html/ModifyJson.htm

JObject に変換した後に、名前付きインデックスで検索ができます。

string rssTitle = (string)rss["channel"]["title"];

ExDoc の場合は、/ 演算子や % 演算子をオーバーライドすることによって、doc * “apikey” のような構文を実現していますが、ああ、なるほど名前付き配列でも十分ですよね。dynamic 版もあって、PHP の XML 風に要素名を連ねることもできます。
内部構造的には、同じことをやっているので、同じ構文が使えても良いかなと思っています。

ExDoc.Json も同じ

ExDoc.Json も作ってみましたが、内部的には ExDoc.Yaml と変わりません。Yaml も Json もハッシュとリストでできているので、似た感じの XML が出来上がります。ただし、Json の場合、長いデータもハッシュに置くことが多いので、ハッシュ値を属性に置くか、要素に置くかの選択ができるようにしました。

public void demo1()
{
    string json = @"
{
 'CPU': 'Intel',
 'PSU': '500W',
 'Drives': {
  set1: 'DVD read/writer',
  set2: '500 gigabyte hard drive',
  set3: '200 gigabype hard drive'
 },
 'Languages': [
  'C#',
  'F#',
  'Visual Basic'
 ]
}";

    var jdoc = JToken.Parse(json);
    var xdoc = jdoc.ToXDocument();
    Debug.WriteLine(xdoc.ToString());
    var doc = ExDocument.Load(xdoc);

    var lang = doc * "Languages";
    foreach (var it in lang)
    {
        Debug.WriteLine("lang" + (string)it);
    }
}

こんな風に入れ子になった JSON の場合、Drives のハッシュをそのまま属性にしてしまうと、ちょっと見づらくなります。

<root CPU=&quot;Intel&quot; PSU=&quot;500W&quot;>
  <Drives set1=&quot;DVD read/writer&quot; set2=&quot;500 gigabyte hard drive&quot; set3=&quot;200 gigabype hard drive&quot; />
  <Languages>C#</Languages>
  <Languages>F#</Languages>
  <Languages>Visual Basic</Languages>
</root>

XML に変換するときに要素出力を優先(XmlPriority.Element)にしておくと、

    var xdoc = jdoc.ToXDocument(XmlPriority.Element);

下記のように、すべてのデータが要素になりようにします。XML 形式にしてしまうと冗長ですが、XElement で LINQ したり、ExDoc で検索したりするときには便利でしょう。

<root>
  <CPU>Intel</CPU>
  <PSU>500W</PSU>
  <Drives>
    <set1>DVD read/writer</set1>
    <set2>500 gigabyte hard drive</set2>
    <set3>200 gigabype hard drive</set3>
  </Drives>
  <Languages>C#</Languages>
  <Languages>F#</Languages>
  <Languages>Visual Basic</Languages>
</root>

ちなみに、Json.NET の内部構造を探っているときに分かったのですが、XPath のような仕組みを作るためにパス部分(ハッシュ名)をすべて持っているんですよね。ハイパフォーマンスな分、メモリは食うかもしれません….が、Web API でやり取りするぐらいのでデータならば別にどうということはないのですが。

追記:2014/10/29
Languages のところが、リストっぽくなくてアクセスしにくいので item タグを使うように変更しよう。

<Languages>
 <item>C#</item>
 <item>F#</item>
 <item>Visual Basic</item>
</Languages>

 

今後の予定

だいたいは思う通りに動いたので、今度は値を変更するところを実装しようかなと思ってます。以前、少し実装はしてみたもの、ExDoc の / 演算子と相性が悪くて、どうもうまくいかないのですが、Json.NET のように KeyValue を使って添え字に名前を使えば、書式が簡単になりそうです。

doc._["Languages"][2] = "Visual Basic.NET" ;

な感じで変更できればよいかと。

あと、XLTS か Xml schema な感じで、元の XDocument 構造を他の XDocument にマッピングする写像っぽい使い方ができると良いと思ってます。複雑な XML や乱雑な HTML データから、目的の XML データを取り出すみたいな使い方です。クエリを使って、直接 XML フォーマット(この場合は XElement ツリー)を作るところまでできれば、後は Json や Yaml に再フォーマットするのは難しくはないかと思ってます。

カテゴリー: 開発, C#, EXDoc | ヒアドキュメントっぽく Yaml を書くための ExDoc.Yaml をリリース はコメントを受け付けていません

新 Mac mini で Xamarin 環境を整える

先日発売された Mac mini http://store.apple.com/jp/buy-mac/mac-mini に Xamarin 環境を構築しています。1.4 GHz Mac mini で直前よりもランクが落ちる感じで、なんだかなーという感じなのですが、まあ、それはそれとしてセッティング。実は、mac mini の新型は出ないと思って、発表の直前に注文はしたんですよね…でもって、発表があったものだからキャンセルをして注文し直したという…。CPU スペック的には mac book air と同じなので開発環境としては問題ないんでしょうが。ディスクが HDD なのがちょっと気になるところです。念のため、メモリは 8GB にアップさせています。ちなみに、ストレージを SSD にアップグレードしてしまうと、Mac book air と同じ値段になってしまう(苦笑)なので、そっちがお勧めです。

https://pbs.twimg.com/media/B0rkkbNCAAAjl3L.jpg:large

上にあるのが新 mac mini で、下にあるのが前々 mac mini ですね。前々 mac mini は core 2 なので今となっては結構遅いです(当時としてもあまり早いほうではなかった気が。入門版の位置づけだったので)。

開発環境として使う

手元の mac book air もそうなのですが、完全に開発環境として使っていて、メールの設定や Office 製品のインストールすらしていません。画面キャプチャ用のツールと、リモートデスクトップ関連のツールだけしか入っていないという環境です。
仮想環境は使わず、PC からリモートで動かすのみなので、ストレージの容量はそれほど必要ありません。なので、HDD よりも SSD のほうが適しているのですが、まあ、対費用効果を鑑みてというところですね。仮想環境上で Windows + Visual Studio を動かす場合は、到底 mac mini のスペックでは無理です。

  • Xamarin Studio
  • Xamarin Android Player
  • splashtop personal

だけの環境です。Windows のほうで VNC クライアントを使えば、splashtop を入れる必要はないのですが、日本語の 109 キーボードが誤認識するので、これを使っています…が、後述するように 新しい mac mini というか yosemite は日本語キーボード自体を認識しないようで、splashtop をつかっても VNC を使ってもキーボードに関しては US キーボードを使っていると同じ状態になります。

Visual Studio から iOS シミュレータに接続する

Xamarin.iOS のバージョンを Windows/Mac で揃えて、すんなりと動きます。特に動作が遅いというわけでもなさそうです。ネットワーク的に頻繁に PC とアクセスするので、WiFi 接続よりも有線LAN接続にしておいたほうが無難でしょう。

image

初期状態の場合、iOS シミュレータは、8.1 しか入っていないので、念のため iOS 7.1 のも入れておきます。Xcode を開いて、「Xcode」→「Preference」で、Downloads のタブを開くと旧バージョンの iOS 7.1 Simulator をダウンロードできます。

image

この mac 自体が新品なので、それ以前のバージョンをダウンロードできませんが、xcode を古くすれば大丈夫なのかな?

一日ほどぱらぱらと動かしてていた感じでは開発環境としては問題ありません。時折、Xamarin Studio で重たい感じがするのはキャッシュの類でしょう。SSD ならば、この手のアクセス不具合が減るのですが、直接 Mac 上の Xamarin Studio で編集することは少ないので、これで十分です。手元にあるのが、前々 mac なので、かなり遅くて閉口したためかもしれません。

Xamarin Studio で iOS シミュレーターを動かした状態です。

image

日本語キーボードが認識されにくい

以前の mac mini の問題として日本語の jis キーボードが認識されませんでした。これは、jis 109 のキーボードレイアウトが mac mini だけ持っていない(mac book air とかは持っている)ので、VNC で接続すると、@ が打てなくて(場所が変わっていて)プログラミングがしにくかったんですよね。@ は、objective-C で頻繁に出てくるので、結構なストレスなのです。

splashtop を使うと、この問題が回避されて、本来の日本語キーボードのレイアウト通りに表示されるようになっていたのですが、新 mac mini では、その問題が再発生しています。

「認識されにくい」と書くのは、たまにきちんと認識されるからです。どういうタイミングなのか分かりませんが、接続状態によって US キーボードに間違われたり、日本語キーボードとして正しく認識されたりします。

image

キーボードの設定を見ると、英字のレイアウトが「U.S.」になってしまいます。実は、この選択肢に Japanese が現れないので、mac mini は以前どおり、日本語キーボードのレイアウトは存在しないのかもしれません。これが mac book air の場合には入っているので、何らかのハードウェア的な制限かもしれません。

Yosemite で Windows からのファイル共有ができなくなった?

新しい OS X ( Yosemite ) では、最初のログインに iCloud に連携させた Apple ID(でいいのかな?)が使われます。なんとなく、Apple ID のほうに統合しておくと、Windows とのファイル共有ができなくなります。

本来ならば、SMB を使うにチェックを入れて、ユーザーのアカウントにチェックを入れれば、Windows からファイル共有でフォルダへの読み書きができるようになるのですが、ここのチェックが入れられなくなります。おそらく、Apple ID で管理するので、Windows から ユーザ名/パスワードでアクセスできない、ってことなのでしょうが非常に不便です。

image

PC と Mac 間でファイルのやり取りをするときに、PC からコピーができなくなります。

回避策としては、

  1. アクセス用にユーザ名/パスワード形式で、ログインユーザーを新しく作る。
  2. 「共有フォルダ」にアクセス用のフォルダを「+」で追加する。
  3. アクセス用ユーザーを、ユーザーに「+」で追加する。
  4. アクセス用ユーザーに、自分のフォルダへのアクセス権限「読み/書き」を与える。

image

私の場合「増田智明(masuda)」というユーザーで普段はログインしておいて、Windows からファイル共有するときは tomoaki というユーザーを使うことになります。Windows からネットワークでアクセスする時に、初回だけユーザー名とパスワードが必要になります。後は、Windows が覚えておいてくれるので(時々忘れますが)、普段通りアクセスできます。

image

アクセス設定をした直後は、うまく設定が反映されていないことが多いので、しばらくして Windows のネットワークを最新にしてアクセスしてみてください。多人数のネットワークの時は、セキュリティ上の問題がありますが、ローカルの開発環境では大丈夫でしょう。

値段的にどうなのか?

実は、開発環境を整えるだけでも結構な値段になります。Visual Studio + Xamarin.iOS の組み合わせだけで年間20万円は下りません。私の場合 Microsoft MVP の関係で、どちらも無料で使っているので mac mini を揃えるだけで済むのですが、個人的な開発をする場合、この金額は結構な負担です。今回の mac mini は最低ランクの 1.6 GHz ですが、メモリだけを 8GB にアップグレードしました。消費税を入れて 7万円弱というところなのです。これ以上のスペックを求めると、先に書いた通り mac book air とほとんど値段が変わりません。おそらく、mac book air も mac mini と CPU スペックは変わらないので、ディスプレイが付いているし、キーボードが付いているし、SSD だし、で良いことづくめです。なので、10万円程度の予算があれば、mac book air のほうがベターでしょう。そういう意味では、5万円ちょっと10万円以下の層で構築するのがベターなような気がします。

そうなると、SSD へのアップグレードとかは色々諦めて、最初のエントリーレベルとしての mac mini 購入を考えたほうがよさそうです。勿論、開発環境でなければ(インテリアとしても含めて)もうちょっと HDD が欲しいところですが、そうなるとディスプレイ付きで iMac にしてしまったほうが良いという感じですね。私の場合、スペースの関係上ディスプレイは必要ないので iMac よりは mac mini のほうが適切なのですが。どちらにせよ、同レベルの PC を買うよりは割高になるのは仕方がないところです。

カテゴリー: 開発 | 新 Mac mini で Xamarin 環境を整える はコメントを受け付けていません

F# の判別共用体を C# で使いやすいようにキャストする

F# で lex/yacc っぽいものを作っていると判別共用体(Discriminated Unions)が便利なので、よく使うのでうのですが「C# で使う時はどうするのか?」と聞かれて、はて?と思ってしまいました。Xamarin.Forms のパーサを作っているときは、そのあたりは微妙に避けて(よくわからなかったので)C# からは直接判別共用体を使わないような工夫をしています。

が、Optional を使ったり Choice を使ったりすると(私自身は使ってないけど)、このあたりはどうするのか?って話です。

判別共用体を作る

他の場合も一緒だと思うので、元ネタの判別共用体を作ります。C/C++ で言えば union なので、そんなに違和感はありません。

type A =
    | STR of string
    | INT of int
    | KEYVALUE of key:string * value:string

判別共用体を使う

判別共用体が便利なのは、利用するときに match で判断できるところです。C/C++ の union の場合は type を内部に持たせるだろうし、Variant の場合も似たり寄ったりです。メモリ効率はどうなのかは気になるところですが、そのあたりは .NET なので、別々に持っているのかも。

let go() =
    let message a =
        let msg =
            match a with
            | A.STR(s) -> &quot;string is &quot; + s
            | A.INT(i) -> &quot;int is &quot; + i.ToString()
            | A.KEYVALUE(k,v) -> &quot;pair is &quot; + k + &quot;, &quot; + v
        printfn &quot;%A&quot; msg

    let a = A.STR(&quot;masuda&quot;)
    message a
    let b = A.KEYVALUE(&quot;address&quot;,&quot;itabashi&quot;)
    message b

オブジェクトを作るときは、A.STR あるいは STR で作れて、チェックするときは match で判別します。便利ですね。
これがどのくらい便利かというと、C# に書いてみるとわかります。

C#で判別共用対を使う

まず、A.STR の場合がそのまま使えないので、create のためのメソッドを作っておきます。
Factory パターンで、create します。

type A =
    | STR of string
    | INT of int
    | KEYVALUE of key:string * value:string

    // C# のための create
    static member create(s:string) = STR(s)
    static member create(i:int) = INT(i)
    static member create(k:string, v:string) = KEYVALUE(k,v)

これで、C# から作成するときは、create メソッドを使えばよいことになります。

var a = A.create("masuda");

F# の match の部分はどうなるかというと、結構面倒です。
これは、判別共用体 A クラスの内容をコンソールに出力しているだけなのですが、IsSTR プロパティでチェックをした後に、A.STR でキャストしないといけません。

static void debug( DiscrUnion.A a )
{
    if (a.IsSTR)
    {
        string s = (a as A.STR).Item;
        Console.WriteLine("string is {0}", s);
    }
    else if (a.IsINT)
    {
        int i = (a as A.INT).Item;
        Console.WriteLine("int is {0}", i);
    } else if ( a.IsKEYVALUE )
    {
        string k = (a as A.KEYVALUE).key;
        string v = (a as A.KEYVALUE).value;
        Console.WriteLine("pair is {0}, {1}", k, v);
    }
    else
    {
        Console.WriteLine("error");
    }
}

F# の match に比べるとかなり冗長な感じです。

これが面倒なので、C# に判別共用体クラスを公開するのはやめていたのですが、どうしても公開する必要があるならば、キャストを作ればよかろう、ってことに先日気づきました。
F# でも op_Explicit や op_Implicit メソッドを書くことによって、明示的なキャストと暗黙のキャストを作ることができます。

C# に公開するキャストメソッドを作る

type A =
    | STR of string
    | INT of int
    | KEYVALUE of key:string * value:string

    // C# のための create
    static member create(s:string) = STR(s)
    static member create(i:int) = INT(i)
    static member create(k:string, v:string) = KEYVALUE(k,v)

    // C# のための明示的なキャスト用
    static member op_Explicit (a:A) : string =
        match a with
        | A.STR(s) -> s
        | _ -> &quot;&quot;
    static member op_Explicit (a:A) : int =
        match a with
        | A.INT(i) -> i
        | _ -> 0
    static member op_Explicit (a:A) : System.Tuple<string,string> =
        match a with
        | A.KEYVALUE(k,v) -> new System.Tuple<string,string>(k,v)
        | _ -> new System.Tuple<string,string>(&quot;&quot;,&quot;&quot;)

    // こっちのほうが便利
    member this.ToKeyValue(): System.Tuple<string,string> =
        match this with
        | A.KEYVALUE(k,v) -> new System.Tuple<string,string>(k,v)
        | _ -> new System.Tuple<string,string>(&quot;&quot;,&quot;&quot;)

op_Explicit メソッドを作っておくと C# で (string)a のように明示的にキャストしたときと同じになります。

var a = A.create("masuda");
string aa = (string)a;

いちいち、IsSTR でチェックしなくてよいので、これでよさそうですね。先の op_Explicit メソッドでは string 以外のときは “” で空文字列を返していますが、failwith にして例外にしてもよいでしょう。

KeyValue のような Tuple を返す時には、F# のものを返しても良いのですが、System.Tuple に書き直しています。このため、キャスト自体が面倒で、下記なことになります。

var b = A.create(&quot;name&quot;, &quot;tomoaki&quot;);
var bb = (Tuple<string, string>)b;
Console.WriteLine(&quot;bb is tuple {0}, {1}&quot;, bb.Item1, bb.Item2);

型推論の var で受ければよいのでは?と思うところですが、var で受けてしまうと判別共用体の A クラスのままになるので都合が悪いのです。
こういう場合は、素直に ToKeyValue メソッドを作って、インテリセンスを効かせたほうが分かりやすいでしょう。

as ではキャストできない

実は、ひとつ落とし穴があって、a as string のようなキャストはできません。変数 a は A クラスなので、as で Type チェックをすると A 自身が返ってくるためです。なので、(string)a のように「明示的にキャスト」をしないといけないという罠に陥ります。このあたりは、ローカルルールということで、要注意です。

あと、暗黙のキャストを作ろうとすると「暗黙のキャスト」以外ができなくなります。先の op_Explicit を op_Implict に書き換えると、暗黙のキャストになって (string) 部分が要らなくて便利そうなのですが、逆に (string) を付けるとコンパイルエラーになる、という不思議なことになります。

// 暗黙のキャストを使う
string aa = a;

これはこれで、var が使えなくなるので不便な感じですよね。また、op_Explicit と op_Implict は同時に定義できないので、どちらか一方だけを使うことになります。これも変な仕様ですが、まあ、そのあたりも含めて注意して作ると、うまく C# で使える判別共用体が作れます。

カテゴリー: C#, F# | F# の判別共用体を C# で使いやすいようにキャストする はコメントを受け付けていません

Yaml を利用して C# でヒアドキュメントを考える

XAML + XDocument + XamlReader.Load を使うと、ヒアドキュメントっぽくコードに XAML を書くことができます。

[WinRT] XElement を使い XAML を構築して動的に XamlReader.Load で読み込む技 | Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/6556

な感じで、XElement を使って構築してもよいし、文字列で XAML を書いてもよい(実際 Storyboard のクローンを作るときは、そうしています)。VB であれば XML 構文を使えばよいのです。
が、ヒアドキュメントで書くにせよ、外部ファイルの読み込み(あるいはリソースからの読み込み)であっても、XML を手書きするのがちょっと面倒で、特に「閉じタグ」の問題が関わってきてしまいます。Visual Studio 付属の XML エディタを使って作ればよい(単純に拡張子を .xml にするだけ)なものの、できれば「閉じタグ」なしで書いていきたい。

XElement の羅列のほうも、閉じタグではないですが、閉じ括弧「)」が頻発します。適切なインデントを付ければ間違いは少ないのですが、そもそもが適切なインデントが付いているはずなので、閉じ括弧はいらないはずです。

Yaml には閉じタグがない

YAMLAin’t Markup Language (YAML) Version 1.2
http://www.yaml.org/spec/1.2/spec.html
C#でYAMLを使えるか試してみた | OPC Diary
http://opcdiary.net/?p=25878
NuGet Gallery | FsYaml 1.1.3
https://www.nuget.org/packages/FsYaml/
閉じタグを超えた先に僕が見た景色とは
http://www.slideshare.net/muyuu/ss-40425076

最後のものは Yaml ではありませんが、Jade という Yaml と似た構文で HTML タグを生成するフレームワークです。

Jade について。
https://gist.github.com/japboy/5402844

を見ると Haml という軽量 HTML 構文から影響を受けているそうなので、Yaml とは潮流が違うみたいですが、

  • インデントを利用して記述する
  • 閉じタグ/括弧が必要ない

ってところで同じでしょう。Yaml 自体は、SPEC で v1.0 以前から見知っていたのですが、Ruby の設定以外にあまり見たことが無くて、それならば XML でも十分ではないか?と思っていたのですよ。ですが、ExDoc を使って検索をしてみると、C# でヒアドキュメントの可能性が出てくるので、そうなると XML 自体の冗長性がちょっと問題になってくるという話です。

Yaml 自体は、YamlDotNet を使うと手軽に読み込めます。取り出しが KeyValue になっているので、今一つ取り出しが面倒ですが、「C#でYAMLを~」の記事のように既存のクラスにマッピングしてから使うのが定番でしょう。ファイル読み込みになっていますが、StringReader を使えば文字列として読み込めるので、コード内のヒアドキュメントとして利用できます。

以下は思考実験です。

Yaml を XML にマッピングする

改めて、Yaml の仕様を見直していたのですが、Yaml にはハッシュとリストしかありません。そういう意味は、XML に属性と値しかないのと似ていて非常にシンプルです。まあ、実際は SPEC を見るとえらい複雑なんですが、まだ v1.0 以前のころはもっとシンプルだったような気が。

とはいえ、適当に XML にマッピングしてみます。XML にマッピングするのは ExDoc で使いやすいのと、他のデータのコンバートしやすいからですね。おそらく JSON からのマッピングも同じになると思います。

Root:
 - person:
   name: masuda
   Age: 46

 

<root>
  <person name='Masuda' age='46' />
</root>

Yaml にはルートは必要ありませんが、仮にルートを決めます。複数並べることがある person タグの場合はリストに、重複しない場合はハッシュで書く、というルールを決めておきます。
上の Yaml から期待されるのは、こんな風に person に属性値で設定された XML ですよね、おそらく。ただし、データとしては属性値であろうと要素の値であろうとどちらでもよいので、

<root>
  <person>
    <name>masuda</name>
    <age>46</age>
  </person>
</root>

こんな感じですべてを要素にするのも可能ですよね。ExDoc の場合は、/ や * 演算子を使うか、% 演算子を使うかという違いが出てきてしまうので、出力される XML は区別されてしまいますが。

先の場合は、person 要素自体が値を持たないので、属性値で要素の値でも似た感じになるのですが、person 要素に値を持たせるようにすると、こんな感じになります。

Root:
 - person: masuda tomoaki
   ID: 100
   Age: 46

person に続くハッシュ値は属性になるというルールを作って、person の属性に設定します。

<root>
  <person ID='100' age='46'>
    Masuda tomoaki
  </person>
</root>

実は、要素だけを使って下記のように作れるのですがあまりお勧めできません。というのも、person の要素を .Value で取れるようにしているのは XElement や ExElement のシンタックスシュガーなところがあって、本来は Text 要素として取ることになります。そうすると、ID タグの後ろとか、age タグの後ろにテキストが入っている場合も探索の対象になって、あまいな部分が多くなります。これは HTML 記法では普通に出てくるものなのですが、ヒアドキュメント的に使いたい場合はこの曖昧さは避けておきたいかなと。

<root>
  <person>
    masuda tomoaki
    <ID>100</ID>
    <age>46</age>
  </person>
</root>

上記の場合、person がリストになっていますが、あえてハッシュの場合も考えてみます。

Root:
  person: masuda tomoaki
    ID: 100
    Age: 46

Root のハッシュとして person を付けます。更に person のハッシュとして ID と Age がある構造ですね。
Yaml ではハッシュの値がハッシュ、ということができるのですが、XML の場合は属性の中に要素を入れることができません。なので、Root のハッシュがさらに子要素を持つような場合には、属性から要素に昇格するという手順が必要そうです。

<root>
  <person ID='100' age='46'>
    Masuda tomoaki
  </person>
</root>

この手順がイリーガルなので Yaml をヒアドキュメントするときに躓きそうな気もするのですが。まあ、子要素は一般的にリスト「-」を使う、というローカルルールにしておけば問題ないかと思います。もともと、ここでの XML の変換自体がローカルルールですから。

Yaml の文章構造をマッピングする

実は Haml という HTML 軽量構文があるので、あまり詳しく作っても仕方がないのですが、ちょっとした RTF っぽい記述をコード内に書き下すことを想定してみます。

HTML:
 Head:
  Title: yaml page
 Body:
  H1: yaml to XML を作る
  P:
    ここに文章を書き下す。

こんな風に Yaml で書いておいてコンバートすると、XHTML(のようなもの)を吐き出します。

<html>
 <head>
  <title>yaml page</title>
 </head>
 <body>
  <h1>yaml to XML を作る</h1>
  <p>ここに文章を書き下す。</p>
 </body>
</html>

XMLの書式に則るので、p タグや br タグの扱いが普段の HTML とは異なりますが、ある程度はこれでできるはずです。このあたりは、XAML の RichTextBlock に渡す糖化構文も合わせて考えていきたいところですね。

カテゴリー: 開発, C#, EXDoc | Yaml を利用して C# でヒアドキュメントを考える はコメントを受け付けていません

[WinRT] XElement を使い XAML を構築して動的に XamlReader.Load で読み込む技

Xamarin.Forms には無い XamlReader なんですが、動的に XAML をロードすることができるので結構便利です、って話を少し(まあ、XAML のパーサーは作ったので、ロードしてやればいいだけなんですけど)。

XamlReader.Load メソッドを使うと XAML 文字列を動的に読み込むことができます。XML を作るときは実は Visual Basic が便利なんですけど、今回は C# で XElement を使って構築します。

XElement で XAML を作成する

こんな風に、チェックボックス(CheckBox)を縦に並べた画面を作ります。これはアンケートツクレールから自動生成するために動的に作っています。

XElement CheckboxToXaml(ExElement el)
{
    string qtext = ((ExElement)(el * "td" % "class" == "qtext")).Value;
    string qbody = ((ExElement)(el * "td" % "class" == "qbody")).Value;
    var lst = el * "input" % "type" == "checkbox";

    var panel = new XElement("StackPanel", new XAttribute("Grid.Row", "1"));
    var hub = new XElement("HubSection",
        new XAttribute("Width", "400"),
        new XAttribute("Header", qtext),
            new XElement("DataTemplate",
                new XElement("Grid",
                    new XElement("Grid.RowDefinitions",
                    new XElement("RowDefinition", new XAttribute("Height", "50")),
                    new XElement("RowDefinition", new XAttribute("Height", "*"))),
                    new XElement("TextBlock",
                        new XAttribute("Grid.Row", "0"),
                        new XAttribute("FontSize", "16"),
                        new XAttribute("TextWrapping", "NoWrap"),
                        new XAttribute("Text", qbody)),
                panel)));
    foreach (var it in lst)
    {
        var node = it.Parent.XElement.NextNode as XText;
        if (node != null)
        {
            string name = it.Parent % "name";
            string value = it.Parent % "value";
            string xname = name.Replace("[]","") + "-" + value;
            _names[xname] = null;

            var ee = new XElement("CheckBox",
                new XAttribute("Content", node.Value),
                new XAttribute("Name", xname));
            panel.Add(ee);
        }
    }
    return hub;
}

まあ、後から気づいたのですが、こんな風にちまちまと XAML を書くぐらいだったら適当なユーザーコントロールにしてしまったほうがいいんですよね。ListView を使って CheckBox を並べるようなユーザコントロールを作って、データバインドを使えば良いわけです。

XElement と XAttribute を使って書き下しているのですが、それぞれのコントロールを使っても同じことができます。実は、このコードは、いちど XAML で書いてから XElement に直しています。このあたり、Visual Basic の場合はヒアドキュメント風に XML を書くことができるのでメリットは大きいのですが…C# だといまいちですね。

XmlReader で文字列の XAML をロードさせる。

あらかじめデザイン上の HubSection のテンプレートを作っておいて、最初と最後のみ残して、その他はすり替えます。XamlReader.Load に渡す XML の xmlns はスキーマを設定しないといけないのですが、そうもそのままではうまくいかないので Replace で逃れています。これは、ルートの XDocument を作るときに指定すればよいでしょう。

// 最初と最後だけ残す
var sec0 = this.hub.Sections[0];
var sece = this.hub.Sections[this.hub.Sections.Count - 1];
this.hub.Sections.Clear();
this.hub.Sections.Add(sec0);

foreach (var it in hubs)
{
    it.SetAttributeValue("ns", "http://schemas.microsoft.com/winfx/2006/xaml/presentation");
    var xml = it.ToString(SaveOptions.None);
    xml = xml.Replace("ns="http", "xmlns="http");
    var sec = XamlReader.Load(xml) as HubSection;
    this.hub.Sections.Add(sec);
}
this.hub.Sections.Add(sece);

コントロールの名前を検索する

実は XAML 文字列で渡すときには問題があって、内部のコントロールに触れないことです。それぞれのコントロールをクラスで組み合わせたときは適当なオブジェクトとして保存しておけばよいのですが、XAML 文字列の場合は、XamlReader.Load の後にオブジェクトができるので、Load した後にオブジェクトを見つける必要があります。
これをどうするのか?ってのが謎なのですが、実は Name プロパティが使えます。XAML で指定するときは x:Name でオブジェクトと結び付けをするのですが、実は FramworkElement に Name プロパティがあるのです。ここに名前を付けておいて、Load 後に検索をします。

// 画面を更新して _names を作る
await Task.Delay(1);

var names = new Dictionary<string, object>();
foreach (var key in _names.Keys)
{
    var obj = FindByName(key, this);
    names[key] = obj;
}
_names = names;

いちど画面に描画してあげてから、Name を検索します。Storyboard のように描画自体がないものはどうなるのかわかりません。アニメーションを使うときには必須なので、これも調べておかないといけませんね。

FindByName メソッドは自作したものです。x:Name を検索するときの FindName メソッドと同じですね。プレロードする XAML の場合は、構築しながら x:Name に対応するオブジェクトを保存していくので高速なのですが、こっちのはコントロールのツリーを探索していくのでちょっと遅いです。とはいえ、画面に表示されるコントロール程度ならば問題ないでしょう。

object FindByName(string name, DependencyObject el , int indent = 0)
{
    string sp = &quot;&quot;;
    for ( int i=0; i<indent; i++ ) sp += &quot; &quot;;
    // Debug.WriteLine(sp + el.GetType().Name);
    var fw = el as FrameworkElement;
    if (fw != null)
    {
        if (fw.Name == name)
        {
            return fw;
        }
    }
    int cnt = VisualTreeHelper.GetChildrenCount( el );
    for (int i = 0; i < cnt; i++)
    {
        var child = VisualTreeHelper.GetChild(el, i);
        var obj = FindByName(name, child, indent + 1);
        if (obj != null)
        {
            return obj;
        }
    }
    return null;
}

そんな訳で、XamlReader.Load を使って動的に XAML をロードすることができます。このぐらいならばユーザコントロールを作ったほうがデザイン的にもよいのですが、実は RichTextBlock を作るときに有効に働きます。その話はまた後日。現在制作中の「ふぁぼ付箋」アプリで使っているテクニックです。

カテゴリー: C#, WinRT | [WinRT] XElement を使い XAML を構築して動的に XamlReader.Load で読み込む技 はコメントを受け付けていません

[WinRT] HttpClient+HtmlAgilityPack+XDocument+ExDoc で HTML データから抽出する話

Web API 華やかな昨今ですが、HTML形式からデータ抽出しないといけないパターンがあります。と言いますか、ちょっと前までは Excel VBA とか DOM を使って抽出したものですが、Wordpress のバックグランドの MySQL から直接取り出したり、そもそも Web API が用意されていたりして、それほど機会は多くないと思うのですが。まあ、ブラウザから手軽に拾えるのは良いかと。

WPF だったりすると、DOM を使って検索する方が早いのですが、ストアアプリだと DOM が取れません。わざわざストアアプリにする理由もないのですが、ダウンロードが手軽なのと、タブレットで使いやすいので敢えてストアアプリを使います。

アンケートツクレール http://enq-maker.com/ 自体が Web API を提供しているのかどうか?は別として、ブラウザから直接抽出を試みます。実は、HTML 形式から抽出する場合も、取り出しやすい HTML 形式と取り出しにくい HTML 形式があります。取り出しやすいのは、name が id が付いていたり、CSS を使ってスタイルが付いている場合ですね。id や name を頼りに検索すれば一発で目的のデータが取り出せます。
取り出しにくいのは、それらの名前がついてないパターンで、前後の文字列を見たり、場合によっては行数をみたりして検索をします。行数の決め打ちはあまり良くなくてデザインが変わってしまうと行数が変わるので非常に変更に弱い作りになってしまいます。大抵の場合は、独自のスタイルが付いてることが多いので、それを目的にして、次のタグとか親タグ、子タグを調べていけばできあがります。

データ自体が JSON や XML で取れるとそのままクラス化して抽出がしやすいのですが、HTML 形式のままだとそうはいきません。試行錯誤が必要になり、また試行錯誤の作業量に見合うデータが取れるかどうかの肝になります。ブラウザの手打ち部分を、そのまま自動化するところが目的ですね。また、見た目のブラウザしか用意されていないパターンでも、プロキシ的にライブラリを噛ませれば Web API にすることもできる、というパターンになります。

データ変換を組み合わせる

HTML 形式の適当なパーサーを書こうかなと思ったところ、HtmlAgilityPack があるのを思い出しました。半年前ぐらいに知って試してみようと思ってそのままだったのですが、先のアンケートアプリで使っています。

  1. HttpCilent クラスを利用して HTML 形式で取得
  2. HtmlAgilityPack ライブラリを利用して DOM 化
  3. XDocument を使って XML 形式に変換
  4. ExDoc を使ってワンライナーなクエリでデータ取得

という流れです。HtmlAgilityPack で XPath を指定してもよいのですが、自前の ExDoc を使いたいので XML 形式(XHTMLもどき)に変換します。

HttpClient でデータ取得

HttpClient オブジェクトを作って、GetStringAsync で全行持って来れば ok です。

var cl = new HttpClient();
var text = await cl.GetStringAsync(url);

この方式の場合は、javascript でデータ加工していた場合は取れないので、その場合は別途 WebView を使います。大抵の場合、jQuery が動いているので、下記のように body 配下を取ってきます。

string[] para = { &quot;$('body').html();&quot; };
string html = await web.InvokeScriptAsync(&quot;eval&quot;, para);
html = &quot;<html><body>&quot; + html + &quot;</body></html>&quot;;
textHtml.Text = html;

どちらの場合も HTML 形式は文字列で取得することになるので、これを DOM にパースする必要があります。

HtmlAgilityPack で DOM を作る

HtmlAgilityPack にはいくつものパラメータがあるのですが、デフォルトの状態で大丈夫です。

var hdoc = new HtmlAgilityPack.HtmlDocument();
hdoc.LoadHtml(text);

HTMLの場合、閉じタグを必要としないタグ(brとかhrとか)があるので、これを適当に補完して貰います。はじめは正確に DOM の形式にならないと、と思っていたのですが、ある一定のアルゴリズムで同じ結果になれば良いわけで、このあたりは大ざっぱでも構いません。見た目が問題なのではなく、データとしての一貫性があればよいのです。

HTMLのDOMをXDocumentに直す

適当に作った拡張クラスで、HtmlAgilityPack の HtmlDocument を XDocument に変換します。コメントなどが「#comment」のようになっているので、これを「_comment」に直しています。後で利用しやすいようにテキスト(#text)は、最初の項目だけ要素の値にしておきます。

public static class HtmlDocumentExtenstions
{
    public static XDocument ToXDocument(this HtmlAgilityPack.HtmlDocument doc)
    {
        try
        {
            var xdoc = new XDocument();
            if (doc.DocumentNode.ChildNodes.Count == 1)
            {
                xdoc.Add(doc.DocumentNode.FirstChild.ToXElement());
            } else
            {
                foreach ( var it in doc.DocumentNode.ChildNodes) {
                    if (it.ChildNodes.Count > 0)
                    {
                        xdoc.Document.Add(it.ToXElement());
                    }
                }
            }
            return xdoc;
        }
        catch (Exception ex)
        {
            var msg = ex.Message;
            return null;
        }
    }
    public static XElement ToXElement(this HtmlAgilityPack.HtmlNode node)
    {
        if (node.Name.StartsWith(&quot;#&quot;))
            return new XElement(node.Name.Replace(&quot;#&quot;, &quot;_&quot;));

        var el = new XElement(node.Name);
        foreach (var it in node.Attributes)
        {
            el.SetAttributeValue(
                it.Name, it.Value);
        }
        foreach (var it in node.ChildNodes)
        {
            if (it.Name == &quot;#text&quot;)
            {
                el.Add(new XText(it.InnerText));
            }
            else
            {
                el.Add(it.ToXElement());
            }
        }
        return el;
    }
}

利用するときは、こんな感じで一発で変換します。

var xdoc = hdoc.ToXDocument();

XDocument を ExDocument に直す

ExDocument の Load メソッドを使うだけです。

var doc = ExDocument.Load(xdoc);

moonmile/ExDoc
https://github.com/moonmile/ExDoc

後で NuGet にもしておきます。

ExDoc で検索する

こんな風に、<td class=”qtext” … > 要素を取り出します。

var lst = doc * "td" % "class" == "qtext";

結果は List になっていて、マッチした要素をすべて取るのですが、ひとつだけと決まっているのであれば、

ExElement lst = doc * "td" % "class" == "qtext";

こんな風に、ExElement 型で受けることができます。List<ExElement> と ExElement の両方を受けることができるように暗黙のキャストを使ったトリックです。なので、型指定をするとその型に変換されるようになっていて、var で推論させるとコレクションが取れるのです。
実は、このトリックは F# と相性が悪くていちいち op_implict でキャストしないといけないのですが。まあ、C# オンリーの技ということで良しとしましょう。

もうちょっと複雑な例としては、

ExElement lpage = (doc * "div" % "id" == "left") * "img" % "class" == "image";

<div id=”left”> の中にある <img class=”image”> を取ってきます。括弧が必要なのがいまひとつなのですが、演算子 * と % を使って次々とつなげていけます。* 演算子は子孫要素を検索して、/ 演算子は子要素のみを検索対象にします(ちなみに / 演算子のほうはバグが入っているらしくうまくいかないこともあるので、* 演算子を使ったほうが無難です)。

親要素は Parent プロパティで取得ができるので、el.Parent.Parent のように親の親を示すこともできます。目的の要素を見つけたら、その親にさかのぼって周辺のデータを取得する、という方法にも使えます。
要は、かっちりした形式ではなくて、なんらかの試行錯誤が必要なときに使えるライブラリです。遅延処理にはなっていないので、いちいち List を作ってしまうのですが、HTML からパースする分にはこれで十分かなと。イミディエイトウィンドウで、ちまちま検索するのにも利用できます、ってことで。

サンプル

アンケートツクレールで作成したアンケートをストアアプリで投稿するツール
https://github.com/moonmile/NetLabEnquete

 

カテゴリー: C#, EXDoc, WinRT | [WinRT] HttpClient+HtmlAgilityPack+XDocument+ExDoc で HTML データから抽出する話 はコメントを受け付けていません

[Xamarin] Visual Studio から Mac に iOS SDK Synchronization できない/iOS シミュレータに接続できないときの解決方法

たぶん、自分の環境前提かもしれませんが、一応メモ的に。

何かのはずみで「iOS SDK Synchronization」の Check Now がクリックできなくなって、Mac の MonoTouch との同期ができなくなることがあります。何故、こんなことになるのか分からないのですが、過去に2度ほど経験して、今回が3回目。

image

このチェックができないと、Visual Studio から Mac の iOS シミュレータに接続できなくて困った状態になるんですよね。暫くして、Xamarin がバージョンアップされると直ったりするのですが、今回は直近で仕事で使うためにいくつか調べました。

公式な回答としては、下記のように手動でシンクロする方法が示されていますが、うまくいきませんでした。回答自体が以前のバージョンなので(確か、この時にも Visual Studio からアクセスができなくておかしなことになった気が)、うまくいかないのかもしれません。

Downgrade or ignore iOS SDK sync error “The SDK synchronization returned with error Unknown” – Xamarin Forums
http://forums.xamarin.com/discussion/19540/unable-to-connect-to-server-and-the-sdk-synchronization-returned-with-error-unknown

先の Check Now が押せる状態になると、タスクバーに MonoTouch を同期させてください、というメッセージがでます。これをクリックして同期さえるわけですが、なんらかのタイミングでこのメッセージ自体がでなくなってしまいます。

image

たぶん、↑のが出していると思うんですよね。

でもって、サービス自体は↓ではないかと。

image

タスクマネージャを開くと「Bonjour Service」というものがあります。おそらく、これがシンクロを管理しているものです。このサービスを再起動させることによって、うまく同期が始まります。何かのフラグかなんかが引っ掛かっているような気がするんですよね。ちなみに、PC を再起動しても Xamarin を再インストールしても、この内部的なフラグはクリアされなくて、残っているようです。曖昧ですが、そんな感じで「再起動」するとうまくいきます。

ちなみに、Xamarin.iOS Build Host Diagnosis で疎通チェックをすると、Connection to Mac server で失敗した状態になっています…が、これで iOS シミュレーターに接続できる状態です。以前は、Failed のままだとシミュレータに接続できなかったので、どこかの時点で内部的に変わったのかもしれません。

image

ちなみに、iOS シミュレータに接続できない状態の時は、最後の Comparing のところが Failed になっていて、上の項目は Passed になっていました。何か変な状態になっているようですが、ひとまずこれで Visual Studio から iOS シミュレータに接続ができます。

カテゴリー: Xamarin | [Xamarin] Visual Studio から Mac に iOS SDK Synchronization できない/iOS シミュレータに接続できないときの解決方法 はコメントを受け付けていません