プロ生ちゃんが聞く!

3 1月

久しぶりにtwitter以外で文章を書いたんだ。僕はキメ顔でそう言った。

プロ生ちゃんが聞く! 2014年プログラミング言語動向

さて、このインタビューで出てきたRoslynっていうものについて、少しフォローアップをしておきましょう。

コンパイラーは2つある

Roslyn以前のお話。あるいは、Roslynが解決する問題。

コンパイラーは2つ保守されています(C#に限った話ではなくて、例えばJavaなんかでも)。要するに、ソースコードをILやバイトコードに変換するためのものと、統合開発環境(IDE: Integrated Development Environment)がソースコード解析などに使うもの。

後者は最終成果物であるILやバイトコードを生成しないので、正確に言うとコンパイラー(compiler: 翻訳者)ではないんですが(パーサー(parser: 文法を説明するもの)というのが正しい)。

例えばこれはJavaの話なんですが、「JDK 8のプレビューがリリースされたけども、Eclipseのコンパイラーが8未対応だからまだ(最近まで)Java 8は使えない」なんていう不思議な話が聞こえてきます。要するに、(本来の、バイトコードを生成する)Javaコンパイラー的には問題ないコードを、Eclipseはエラーだと認識して警告を発していました。

今までのVisual Studioにも実はこういう問題にあたる可能性はあって、それがないのは単純にマイクロソフトが2重のコストをかけてちゃんとC#コンパイラーとVisual Studio上のC#パーサーが一致するように頑張っている(一致するまで公開されない)からです。

“もう1つのコンパイラー”(IDE上のパーサー)

ではその”もう1つのコンパイラー”がどういうことに使われているのか(つまり、IDEがC#の文法を理解しなければならない理由について)、いくつかの例を見てみましょう。

構文ハイライト

多くのIDEでは、プログラミング言語のキーワードやコメント、型名などにそれぞれ色を付けて、ソースコードを見やすくしています。こういのを、構文ハイライト(syntax highlighting)とか言ったりします。

Figure 1: Visual Studio上に表示したC#コード(色が付く)

ある程度は、正規表現みたいな単純な文字列検索でもできるんですが、C#の場合は特定の文脈でしかキーワード扱いされない単語も多いですし、ちゃんと色付けするためにはIDEがC#の文法を理解する必要があります。

リアルタイムなエラー検出

コンパイル式のプログラミング言語の場合、多くの人為的ミスはコンパイル時に発見されます。

もっというと、IDE上では、コンパイル時どころか、リアルタイムにエラーを発見してその個所を示します。

Figure 2: リアルタイムに検出したエラーが表示されている例(これはVisual Studio 2013にProductivity Power Toolsというプラグインを入れた状態)

コード補完

プログラミング言語では、文脈ごとに、そこに書いて正しく解釈できるコードが結構限られています。そして、限られているのなら自動的に埋める(補完する)こともできます。こういう、自動的に埋めれるものをIDEが埋めてしまう機能をコード補完(code completion)といいます。

例えば、クラス名などを途中まで入力するだけで残りを補完して出したり(IntelliSense)。

Figure 3: クラス名の補完(IntelliSense機能)

解決方法がはっきりしているエラーに対して、その解決方法を提示したり(スマート タグ)。

Figure 4: エラーが出ている箇所に表示されるスマート タグ

Figure 5: スマート タグによるコード自動生成結果

よく使う定型文を、短縮形のキーワードを使ってコード生成したり(コード スニペット)。

Figure 6: コード スニペットの例

Figure 7: コード スニペットによるコード自動生成結果

リファクタリング

取り急ぎ動くようになるまで書き殴ったソースコードは、往々にして、機械的な書き替えでより読みやすいコードに修正できたりします(機能はそのままで、読みやすいよう、今後の機能追加がしやすいように書き替えることをリファクタリング(refactoring)といいます)。当然、機械的にできることはIDEにやらせるべきです。

Figure 8: メソッド抽出(Visual Studioのリファクタリング機能の1つ)の例

Figure 9: メソッド抽出の結果

つまるところ

IDE上では、バックグラウンドで常にコンパイラーが動いていて、一字一字書き替えるたびに、その書いたソースコードがどういうものかという情報を更新し続けています。このコンパイラーには以下のような要件が求められます。

  • ソースコードのどこからどこまで(何行何列目)が何かという情報がとれる
  • 文脈に応じてソースコードを生成したり、書き替えたりできる
  • リアルタイム処理を必要とするので、パフォーマンスも求められる

コンパイラーを1つに

もちろん、2つの異なるコンパイラーを保守するのは容易ではありません。プログラミング言語への新機能の追加には2重の労力がかかります。余計な労力がかかるということは、新機能の追加にも慎重にならざるを得ません(開発リソースは有限です)。コンパイラーを1つにできるのならぜひとも1つにしたいです。

コンパイラーが2つになる理由は、(ILを生成する)通常のコンパイラーが最終成果物(要するにIL)以外のことに無頓着で、IDEが必要とする情報を返さないことにあります。

なら、最初から、IL生成という最終目標に加えてIDEが求める中間情報を取れて、ソースコードの自動書き換え機能も想定していて、リアルタイム処理にも耐えうるパフォーマンスが出るコンパイラーを作れば、コンパイラーは1つだけにできます。

これがRoslynというプロジェクトの目標です。当初考えられていた以上にこの目標は大変(既存の、2つにわかれているコンパイラーとの互換性維持も大変さの理由の1つですが)で、工期は長くなってしまいました(Roslynというコードネームのこのプロジェクトの発足が公開されたのは2011年)が、今年ようやく完成が見えてきました。

そして完成すれば、C#への新機能追加のコストが激減します。

あとがたりっ!

26 12月

25日間、画像が1枚もないってどーゆーことー?

ゴチャゴチャやかましいぞ!外野

こっちはでっかいコストかけてやってんだぞ

どれだけの覚悟決めてここに書いてると思ってんだ

そんな苦労も知らないで

ボケナスどもぉ

髪型の元ネタのパロディがどうしてもやりたかったのね?

あんた、完全に元ネタの2Pカラーになってるけども…

はい、すみません。

いつも通り、ほんの出来心だったんです。

ていうか、24日のは何なの?なんで私が一人だって決めつけるわけ?

えっ?

えっ!?

えっ?

(くそー、VBたんまで…)

でもほんと、このブログこの後どうするのー?

どうしましょう?

ノープラン?

Exactly(その通りでございます)

ブログって、継続的にやらないとPV伸びなくない?

エレス コレクート(君は正解だ!!)

それでも考えなし?

ええ、そんな余裕ございませんでした。

勿体ないですよね、ずっとは無理だし、単発なら原稿料もらえるところに出したいし!

ぶっちゃけるわね、あんた。

まあ、ここの使い道はまたおいおい考えます。

考えますというか、なんかまた唐突に思いついたら。

えーっと、最後に、読者の皆様に感謝の言葉を。

思いっきりガチで、容赦なく長文でしたが、お付き合いいただいてありがとうございます。

一発ネタは一旦の終了となりますが、C#たんは不滅です。始まりの魔法使いのごとく不滅です。

コンゴトモヨロシクお願いいたします!

C#っ! to the future

25 12月

ネタ切れネタ切れって 言いたい事言いやがって ネタなんて最初からねーんだよ! ブロガーが消費してんのは 寿命だけだオラ!

(意訳: ネタ要素薄くてごめんなさい。)

 

最後に、この無謀な25日間の内容から、要点を抜き出しましょう。将来の方向性の示唆にもなると思います。

上昇傾向

初日に、C#の歴史を振り返ってみました。

 

最初は政治的(SUNとの利害関係) 、経済的(DelphiのアーキテクトであるAnders Hejlsbergがマイクロソフトに引き抜かれてる)な理由で始まったC#ですが、3.0、4.0とバージョン アップを重ね、非常に素晴らしい言語に育ちました。まだまだ伸びるでしょう。

こんな話もあります:

1企業の調査なので、まあ、話半分にとらえるべきかもしれませんが、C#はずっと伸び続けています。

昔だったらJavaなどが採用されそうだったような状況で、C#が採用される場面も出てきています。Unity、PlayStation Suiteと、ゲーム向け開発プラットフォームでの採用が続きました。

ちなみに、日本においても、C#関連のホームページのアクセス数や、書籍の売り上げ、伸びてきているようです。

データ処理と非同期

C# 3.0以降の進化の方向性は、データ処理と非同期処理に焦点が当たっています(C# 2.0までは、いわば基礎固めと言った感じで、既存言語と比べてそれほど目新しいことはしていません)。

 

非同期処理は、これからもまだまだ進歩していく分野でしょう。データ処理においても、ネットワーク越しに別のサーバーからデータを取ってくることが多く、非同期I/Oが重要です。

広い範囲の視野持ってほしい

この25日間で、非常に広い範囲の話をしてきました。.NET自身が広い範囲をカバーしているというのもあります。

 

内部に踏み込んだ話もいくつかしました。

 

設計パターンみたいな話もしました。

 

そして、プログラミングはあくまでも手段であって目的ではありません。広く使える手段となる.NETでは、広い目的を果たせます。5日目には、統計の話なんかもしました。

 

どれも重要なことだと思って、25個の話を書きました。

覚えることが多くて大変と思うかもしれないですが、今、.NETに限らず、IT技術者に求められている必要な知識だと思います。

今は、分業化も進んでいて、各個人が直接必要となる範囲は狭いかもしれませんが、協業相手との円滑なコミュニケーションのためにも、概要くらいは広く知る心構えを持ってください。

共通ライブラリ

何回かは、.NETのライブラリの紹介などもしました。

ほんの一角しか紹介できませんでしたが、.NETには様々なライブラリがあります。

18日目に話しましたが、今は、言語を覚えることよりも、ライブラリを覚えることの方が重要、かつ、大変です。

1つのライブラリを、いろんな言語から利用できるというのは非常に大事です。これは、.NETだけでなく、他の環境でも言えることでしょう。ネイティブと.NETでの共通利用、静的言語(C#やVBなど)と動的言語(IronPythonなど)との間の相互運用も重要です。

銀の弾丸はない

「AかBかどっちがいい?」みたいな質問の答えは、だいたい、「両方」もしくは「中間」になります。

 

GUIかCUIかと言われたら、両方。

静的か動的かと言われたら、両方。

ネイティブかマネージかと言われたら、両方。

ウェブかクライアントかと言われたら、両方。

OOPか関数型かと言われたら、両方。

 

それが現実です。

重要なのは、AとBそれぞれ、適切な利用場面がどこか、そして、選べるかどうかです。

ツール連携

コンパイル時と実行時では、コンパイル時にエラーが発覚してくれた方が、エラーを発見しやすいです。Visual Studioに至っては、コンパイル時どころか、タイピングしたそばからコードが解析されて、リアルタイムにエラー内容が見えます。それが静的な言語のよさでもあります。

一方、動的言語と呼ばれるようなタイプのプログラミング言語は、スクリプティングやメタプログラミングしやすいという利点があります。

ここで再び、「AかBか?」と聞かれたら、両方! C#も、動的な特性や、スクリプティング、メタプログラミングの方向に進歩しようとしています。

 

しかしそれでも、基本方針は、可能な限り静的(コンパイル時)処理、そして、Visual Studioとの連携ありきです。先だって、Roslynで、Visual Studioとの連携を深めようとしています。

 

スクリプト(文字ベースの操作)であっても、GUIの補助により生産性を高めることができます。

 

また、C#という言語に新しい機能を入れるにあたっては、ライブラリやVisual Studioまで含めた視点で、慎重に考える必要があります。

 

クロス ターゲットな”コア”

「AもBも」といろいろ求められる昨今、クロス ターゲット、run anywhereに作れる部分と、そうでない部分をきっちりと分離しましょう。

 

「これはクロス ターゲットに利用可能だろう」と思っていたものが、実はそうでなかったりもするので少し注意が必要です。

10年も前だと、ファイル読み書き(.NETでいうとSystem.IO.Fileクラス)が非ポータブルだなんて思いもしなかったものです。今だと、ファイル読み書きはセキュリティ的なお荷物です。

開発プロセス

Visual Studioは、個人のコーディング → 個人のテスト → 開発チームの連携 → 統制・開発・運用含めた連携 と進歩してきています。

 

「ツールに使われてるみたいで嫌」と思うかもしれませんが、ツールの補助は、ある意味教科書みたいなものです。素直に従ってればいいというものでもありませんが、少なくとも、なぜツールがそうなっているかは考えてみた方がいいでしょう。

色々余計な負担になることもあります。しかし、必要なことを色々端折って始めるのは簡単ですが、後からつらくなることが多々あります。いわば、負債と引き換えに歩を進めているようなものです。リリース後の継続運用・継続開発が重要になっている昨今、負債をしょい続けていいものかどうか、良く考える必要があります。

.NET関連技術

25 12月

C#たんは最初から最後までクライマックスだぜ!

 

この記事は、C# Advent Calendarの方の25日目です! 私の1人Advent Calendarの方は、そっちはそっちで書きます!

今日は、C#や.NETと、その周辺のキーワードを網羅的に紹介していこうかと思います。

.NET周辺キーワード

軽く図にしてみました。

 

コア

クロス ターゲットに使える部分です。.NET Frameworkの標準ライブラリの中でも、基礎中の基礎。

  • Text/RegularExpressions: テキスト処理と正規表現
  • Collections: コレクション
  • LINQ: データ列の加工や集計(.NET 3.0以降)
  • Math: 数学関数
  • Numerics: BigInteger(任意精度整数)とComplex(複素数)(.NET 4以降)
  • IO: ファイルなどの入出力
  • Net: ネットワーク アクセス
  • Reflection: 実行時型情報
  • Expressions: 式ツリー(ラムダ式をデータ化)、動的コード生成
  • Task: 同時実行(並列処理、非同期処理)
  • Service Model: サービス化(システムの備品化、疎結合化)
  • MEF (Managed Extensibility Framework): プラグイン拡張

 

クライアント

いわゆるビュー、プレゼンテーション層技術、GUIフレームワークです。XNA以外は、同じスタイルで開発(XAML+C#、Visual StudioやBlendによるRAD開発)できます。ただし、GUIのクロス プラットフォーム開発は割かし幻想で、ターゲットごとに微妙に差があります。

  • WPF: デスクトップ向け
  • Silverlight(ブラウザー): ブラウザー プラグインとして提供。FireFoxや、Safari上でも動きます
    • デスクトップ向けの.NETと比べると、使えるライブラリが少ないです
    • コアの部分は使えます
  • Silverlight(Windows Phone 7): Windows Phone 7向け。
  • Metro/WinRT: Windows 8なタブレット端末向け(現在、早期プレビュー版)
  • XNA: アクション性の高いゲーム向けのフレームワーク
    • イベント駆動型ではなく、メッセージ ループを直接書く
    • Windows PC、Xbox 360、Windows Phone 7上で動きます

 

加えて、ASP.NETでは、HTMLをサーバー上で生成して、クライアント側はブラウザーを使って表示というパターンもあります。HTML5にも対応しています。最近はjQueryに投資しているようです。

通信

WCFは、.NETにおけるサービス化の要です。ネットワークをまたいで、インターフェイスのメソッドを呼び出すようなプロキシの役割を担います。

元々は、いろんなタイプの通信プロトコルを統一的に扱うためのものでしたが、最近はHTTPを使ったウェブ サービスに最も注力しています。

昔は、SOAPというメッセージ交換プロトコルを主軸にしていましたが、今は、REST形式のプロトコルであるODataを主軸としています。XMLだけでなく、JSONにも対応しています。

アプリ サーバー

処理の大部分をサーバー上で行うようなアプリを開発するためのフレームワークとして、ASP.NETがあります。

サーバー上でHTMLを生成してブラウザーで表示する場合もあれば、ウェブ サービス化しておいてクライアント アプリから呼び出す場合もあります。

  • ASP.NET Web Forms: 通信層を隠ぺいして、デスクトップ アプリと同じ感覚でウェブ アプリを作れます
    • 内部を隠ぺいしすぎて不評というのもあったりします
  • ASP.NET MVC: .NET以外の言語のウェブ フレームワークに多い、MVC構造を採用したフレームワーク
    • HTTPを下手に隠ぺいするのはやめて、規約ベースでURLと処理の対応付けします

 

特に、ASP.NET MVCでは、HTMLの生成用のテンプレート部分に、aspx形式と、Razor形式(拡張子cshtmlかvbhtml)を選べます。Razorでは、<%%> のような不恰好なコード ブロックではなく、@ を使って簡潔にコードを書けます。

データ アクセス

C#などの.NET言語からデータベースにアクセスするためのフレームワークとして、ADO.NETというものがあります。

特に、.NET 4から標準に入った、ADO.NET Entity Frameworkというものを使うと、ER図的なデータ設計モデルからデータベースや、エンティティ クラス(.NET側からデータベースにアクセスするために使うクラス)を作ったりすることもできます。

  • Database-First: データベースからエンティティ クラスを生成します
  • Visual-Model-First: Visual Studio上で、ER図(Entity Relationship Diagram)的なGUIを使ってエンティティを設計し、データベースやエンティティ クラスを生成します
  • Code-First: 素のクラス(何も継承しないし、内部に何も特別な処理を書かない、純粋にデータを表すクラス)から、データベースやエンティティ クラスを生成します

サーバー インフラ

  • WF (Windows Workflow Foundation): フローチャート的な処理手順を、GUI上で編集して実行できます
    • SharePointサーバーやTFSのカスタマイズに使えます
    • 次期バージョンでは、バッチ処理をWFで書いて、PowerShellから起動というようなこともできるようになります
  • WIF (Windows Identity Foundation): 認証基盤

サーバー製品

サーバー アプリを作るなら、それを動かすためのサーバー製品が必要になります。オン プレミス(On Premise: 自前でハードウェアを持って自前で管理する)版と、クラウド(PaaS、管理もお任せ)版の両方が提供されています。

  • Windows Server/Window Azure: OS
  • SQL Server/SQL Azure: データベース サーバー
  • AppFabric: サーバー間の連携や、アクセス制御を担うインフラ

サーバー管理は、RDP(リモート デスクトップ接続)かPowerShellを使います。繰り返しになりますが、GUIにもCUIにもそれぞれいいところがあって、両方需要があります。Azure(のVM Role)ではクラウド相手ですらRDP管理できます。

また、Office製品と連携する業務基盤であるSharePointというサーバー製品もあります。OfficeやSharePointのカスタマイズも、Visual Studioと.NETを使ってできます。

開発インフラ

.NETと言えば、強力な統合開発環境。

  • Visual Studio: 説明不要かと思います。.NETの生産性の高さの原動力
  • TFS (Team Foundation Server): バージョン管理、作業項目管理、継続的インテグレーションなどを行うためのサーバー製品
  • Team Foundation Service: TFSのSaaS版。Azure上で稼働(現在、プレビュー版

Visual Studioは、2010から、拡張が簡単になりました。拡張マネージャーというものを使って、サード パーティ製のVisual Studio拡張を簡単にインストール可能です。拡張を作る側は、Visual Studio SDKというものを使います。

Roslynで一番期待されているのも、Visual Studio拡張によるメタプログラミングです。

現状だと、ビルド時コード生成によるメタプログラミングでは、T4テンプレートを使います。

コミュニティ

ライブラリ

現在では、約2年周期の大きなアップデート(Vistaから7にとか、Visual Studio 2008から2010にとか)の合間合間にも、オープン ソースで広くフィードバックを厚めながら新機能を提供しています。

コードの公開にはCodePlexというオープン ソース コミュニティ向けサイトを利用しています。

いくつか例を挙げましょう。

マイクロソフト公式のもの以外にも、コミュニティ ベースのToolkitもあります。

その他、CodePlexには有用なオープン ソース ライブラリがたくさんあるので、サイト内をいろいろ検索してみてください。

こうして作られたライブラリ(マイクロソフト公式の追加ライブラリや、コミュニティ ベースのもの)は、最近だと、NuGetという、オンライン ギャラリー + Visual Studio拡張を通して、簡単にプロジェクトから参照できます。

情報提供

マイクロソフトの開発者向け製品に関する情報は、MSDN(Microsoft Developer Network)というサイトに集約されています。

  • ライブラリ: APIリファレンスなど、学習コンテンツ
    • 初心者が学ぶには詳しすぎてしんどいなんて話もありますが、網羅性と詳細さは非常に良いです
    • 日本からは、「英語の情報があるってことは、まだ日本語未対応なんでしょ。そんな情報要らない」というフィードバックと「英語でもいいから最新の情報もらえないと困る」というフィードバックが半々で、途方に暮れているそうです
    • 「機械翻訳でもいいから早く」と「機械翻訳とか役に立たねー」も半々
  • ブログ: 社員によるブログ
    • 最新の情報はだいたいここ(の本社社員の記事、もちろん英語)から出てきます
  • マガジン: 毎月刊行される情報サイト
    • 元々は本当に紙の冊子も販売されてた
  • フォーラム: フォーラム(掲示板)形式で、質問や意見/要望を受け付けています
  • Code Recipe: コード付きのサンプル/解説置き場
    • 元々は公式コンテンツしかなかったですが、今ではユーザー投稿(誰でも可能)を受け付けています

多様化

C#やVBだけが.NETじゃなく、マイクロソフトだけが.NET提供しているわけではなく、PCだけが.NETの対象ではありません。

  • DLR (Dynamic Language Runtime): .NET上に動的言語を実装するための基盤
    • マイクロソフトの寄与度が高いものでいうと、IronPythonが提供されています
    • その他、IronRubyなど、いくつかの動的言語がDLR化されています
    • DLR上に実装された動的言語からは.NETのライブラリを利用でしますし、動的言語側で作ったクラスなども、C# 4.0のdynamicキーワードなどを使って相互運用可能です
  • mono: オープン ソースな.NET実装です
    • Mac向けやLinux向け、iOS向けやAndroid向けなども提供されています
    • UnityPlayStation Suiteなどのゲーム開発フレームワークでも採用されています
  • Robotics Studio: C#などを使ってロボットを制御
  • .NET Micro Framework:組み込み機器向け.NET
    • OSすら載せたくないような低フットプリント機器向けに、.NETの最低限の機能だけを提供
    • オープン ソース提供されています
    • Porting Kitを使って特定のハードウェア向けにカスタマイズすることもできます
    • 元から対応しているハードウェア基盤の購入もできます
    • モジュールの組み合わせでプロトタイプ作成ができる、.NET Gadgeteerというプロジェクトも

メタプログラミング

24 12月

C++たんがまた今年も一人パーティ用のケーキとシャンパン買ってましたが、皆様いかがお過ごしでしょうか。

 

さて、本日はメタプログラミングがテーマです。

パターン

プログラミングには、「こういう場面はこう書くべきです」というようなパターンがつきものです。

この手のパターンは、昨日も少し話したような一種の「失敗しないための教科書」です。守らないと、アプリの欠損を招く確率を跳ね上げます。それはもう、たいそう跳ね上げます。

ある種のパターンは、ライブラリ化することで回避できたりします。しかし、ライブラリにできないパターンというのもあって、そういうものは、ちゃんとパターンを覚えてコードを書かないといけません。

ということで、言語構文を一通り覚えたら、次は、パターン本を読んで全部覚えろと言われるわけです。

しかし、それを社内すべてのエンジニアに期待できるのかというと、なかなか難しいのが実情です。そして、悪貨は良貨を駆逐する。しっかり勉強してる人が、わかってない人のコードに疲弊して、ばかばかしくなって辞めていくわけです(※末尾に補足あり)。

パターンを言語機能化

ライブラリ化しにくいパターンも、言語機能として何らかのサポートを加えることで回避できることがあります。

「このパターン通りに書け」だと意識の高い人しか実践してくれませんが、「この文法使うと便利だよ」なら割とみんな使ってくれます。

C#にはそんな、パターンだったものを文法化したものがいくつかあります。

イベント

いわゆるイベント駆動型のプログラムを作る場合、オブザーバー パターンというものを使います。C#のイベント構文を使わずに書くと、以下のようなパターンになります。

object _progressSync = new object();
Action<int> _progress;

// イベント ハンドラーの登録
public void AddProgressHandler(Action<int> handler)
{
    lock (_progressSync)
        _progress += handler;
}

// イベント ハンドラーの解除
public void RemoveProgressHandler(Action<int> handler)
{
    lock (_progressSync)
        _progress -= handler;
}

デリゲート(マルチキャスト可能な関数オブジェクト)の概念を持っていない言語だと、もうちょっとめんどくさいパターンになります。

C#の場合、オブザーバー パターンに相当する機能は、イベント構文という専用の構文があって、1行で書けます。

public event EventHandler<int> Progress;

これで、上記のコードと同じ挙動が得られます(具体的な実装はちょっと違いますが)。

イテレーター

データ処理、例えば、データ列の中から特定の条件を満たす要素だけを取り出すというような処理を考えてみましょう。一般に、この手の処理にはイテレーター パターンというものを使います。これも、C#の専用の言語機能に頼らず書くと、以下のようになります。

class WhereEnumerator<T> : IEnumerator<T>, IEnumerable<T>
{
    IEnumerator<T> _e;
    Func<T, bool> _cond;
    public WhereEnumerator(IEnumerator<T> e, Func<T, bool> cond)
    {
        _e = e;
        _cond = cond;
    }

    public T Current { get { return _e.Current; } }

    public bool MoveNext()
    {
        while (_e.MoveNext())
            if (_cond(_e.Current))
                return true;
        return false;
    }

    public IEnumerator<T> GetEnumerator()
    {
        return this;
    }
// 
一部省略
}

public static IEnumerable<T> Where<T>(IEnumerable<T> source, Func<T, bool> cond)
{
    return new WhereEnumerator<T>(source.GetEnumerator(), cond);
}

C#にはイベント構文というものがあって、このパターンを劇的に簡素化できます。以下の通りです。

public static IEnumerable<T> Where<T>(IEnumerable<T> source, Func<T, bool> cond)
{
    foreach (var x in source)
        if (cond(x))
            yield return x;
}

 

それでもまだまだパターン

そんなC#でも、まだまだパターンを書かないといけないことは多いです。

あるオブジェクトのあるプロパティの値が変化したことを、他のオブジェクトに伝えたいことがあります。データベース エンティティ変更追跡とか、GUIへの反映なんかが主だった例です。

この場合、結構面倒なコードを書く必要があります。例えば、XとYという2つのプロパティを持つだけの単純なクラスすら、以下のようになります。

class Point : INotifyPropertyChanged
{
    private int _x;
    public int X
    {
        get { return _x; }
        set { _x = value; RaisePropertyChanged(“X”); }
    }

    private int _y;
    public int Y
    {
        get { return _y; }
        set { _y = value; RaisePropertyChanged(“Y”); }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void RaisePropertyChanged(string name)
    {
        var d = PropertyChanged;
        if (d != null)
            d(thisnew PropertyChangedEventArgs(name));
    }
}

 

メタプログラミング

こういう時、例えば、以下のような簡素なクラスから、先ほどのようなパターンで煩雑化したクラスを自動生成したかったりします。

class PointDefinition
{
    int X;
    int Y;
}

 

こういう発想を、プログラムからプログラムを作るという意味で、メタプログラミング(meta-programming)と呼びます。

こういうのは、動的言語と呼ばれるようなタイプのプログラミング言語が得意とするところです。

まあ、C#でも、少し煩雑ですが、動的コード生成で対処できないことはないです。が、以下のような理由で敬遠されます。

  • なんだかんだ言って結構煩雑
  • この手の処理なら、コンパイル時コード生成でもできるんだから、動的(実行時)に生成したくない
    • コンパイル時にエラーがわからない(実行して初めてわかる)のが嫌
    • 性能を落とすのが嫌

 

なので、「C#にも、C言語の#defineみたいな置換マクロが欲しい」みたいな意見も時々聞きます。ただ、C#の場合には、Visual Studioとの連携も必要なので、マクロ(単純な文字列置換)では難しいです。もし導入しても、Visual Studioの補助が受けれなくなるデメリットの方が大きいです。

T4テンプレート

C#でのメタプログラミングは、本格的にやるならRoslynを待った方がいいかもしれません。

まあ、今現在の次善の策としては、T4テンプレート(Text Template Transformation Toolkit)というものを使うのがいいでしょう。コンパイル時のコード生成用のツールで、Visual Studio 2010からは標準で入っています。

結構慣れるまでが大変、かつ、そんなに使いやすい文法でもないんですが、以下のような感じです。

using System.ComponentModel;

public class <#= Def.Class #> : INotifyPropertyChanged
{
<#
foreach (var p in Def.Properties)
{
#>
    private <#= p.Type #> _<#= p.Name #>;
    public <#= p.Type #> <#= p.Name #>
    {
        get { return _<#= p.Name #>; }
        set { _<#= p.Name #> = value; RaisePropertyChanged(“<#= p.Name #>”); }
    }

<#
}
#>
    public event PropertyChangedEventHandler PropertyChanged;

    private void RaisePropertyChanged(string name)
    {
        var d = PropertyChanged;
        if (d != null)
            d(this, new PropertyChangedEventArgs(name));
    }
}

これで、簡素な定義クラスから、煩雑なパターン生成できます。上記のテンプレートをNotifyPropertyChanged.ttincというファイル名で作ったとして、それとは別に、以下のようなテンプレートを作ります。

<#@ template debug=”false” hostspecific=”false” language=”C#” #>
<#@ output extension=”.cs” #>
<#
var Def = new
{
    Class = “Point”,
    Properties = new[]
    {
        new { Type = “int”, Name = “X” },
        new { Type = “int”, Name = “Y” },
    },
};
#>
<#@include file=”NotifyPropertyChanged.ttinc” #>

その結果、先ほど作ったようなPointクラスが自動生成されます。

メタプログラミングする上で

メタプログラミングするに当たっては、難儀な問題がいろいろあったりします。いくつか説明していきましょう。

覚えるコスト

メタプログラミングは、既存の言語の文法の中に、別の文法を作るようなものです。新しい言語を覚えるコストが余計にかかります。

ツールとの連携

「パターンを覚えるにしても、新しい文法を覚えるにしても、(あるいはライブラリでやるなら)新しいクラスやメソッドを覚えるにしても、覚える量には変わりがないじゃないか」と思うかもしれません。

一般にはその通りなんですが、C#の場合、Visual Studioという強力な補助ツールがあるわけです。クラスやメソッドの追加の場合、Visual Studioの補完を使えます。しかし、新しい文法を考える場合、Visual Studioまで対応させるのは結構難しいです。

先ほどのT4テンプレートが微妙なのも、Visual Studioの補助がいまいちだからというのが大きいです。

読みやすさと書きやすさ

プログラミングという作業では、書きやすさよりも、読みやすさの方が大事です。書いた本人とは違う人がコードを読む機会が多いです。また、自分の書いたコードであっても、ちょっと前のことはすぐに忘れます。

メタプログラミングも、後から読んで困るほどの省略はしてはいけません。

まあ、煩雑なパターン コードよりは読みやすいはずなので、変な略語とかだけ使わなければ大丈夫でしょう。

なんでもはやろうとしない

メタプログラミングは、汎用プログラミング言語の構文に漏れるような、ある特定の領域に対して特化した構文を作るのに使います。

「特定の領域に絞る」というのは非常に重要です。メタプログラミングで何でもはやろうとしないでください。それは、汎用言語構文の役割です。

補足

 

悪貨に駆逐されないために

本題と外れるのでいったんスルーしましたが。

「ダメな人のコードにできる人が疲弊する」というので、本当にまずいのは、組織的な問題の部分です。組織運用の在り方から考えなおす必要があります。

「ダメの人のコード」というように、個人に帰着した問題になっている時点でアウトです。コード レビューなどを通してダメなコードをはじく仕組みを、チーム全体でやっていく必要があります。コードの責任を個人のものにしてはいけません。その責任はチームで持つべきです。

個人からチームへ

23 12月

今日のテーマは共同開発です。

 

非常に大事というか、会社に入ると当たり前な話なわけですが。あんまり学校の授業では出てこないみたいで、学生さんには欠けがちな視点みたいですねぇ。

視野の広がり

Visual Studioというのはソフトウェア開発の生産性を上げるためのツールです。ソフトウェア開発と言っても、いろんな視点があって、いろんな機能提供があります。以下の絵は、Visual Studioの新機能追加の歴史のようなものです。

この視点の変化(というか、視野の広がり)は、Visual Studioに限らず、ソフトウェア開発の現場一般に言えることでしょう。視野は、個人からチームへ、開発チームからビジネス全体へと広がっています。

.NET以外の世界でいうと、

  • エディター(Eclipseなど)
  • ソースコード管理(SubversionやGit)
  • 進行管理(TracやRedmine)
  • 継続的インテグレーション(Jenkinsなど)

など、多くのツールを組み合わせて実現します。

Express版

昨日のテストの話でもしましたね、初心者だと無償のExpress版で十分だと。それは、初心者だとだいたい、個人視点に収まるからです。前節の図で言うと、「開発者」に位置する機能は、Express版でもかなり網羅しています(単体テスト機能はないですが)。

一方、図中の右に行くほど、Visual Studioの上位エディションにしかない機能が増えます。

アプリのライフサイクル管理

開発チームという視点から、ビジネス全体へと視野が広がっているのには、時代の変化という背景もあります。

  • パッケージ売りから継続運用への変化
    • 昔は、一度リリースしてしまったらもうおしまい(あるいは、バージョン アップまで結構間が空く)でしたが、今は、ウェブなどで、継続的に要望が入り、継続的に開発を行う必要があります
  • アジャイル開発
    • 最初に要望を聞いて終わりではなく、細かい単位で要望や優先度の見直しが行われるようになっています
    • そもそも、世情の変化も早く、要望自体が短期間で変化します

開発チームだけで閉じていては、世情の変化に迅速に対応することができず、ビジネスの機会を失います。

アプリは、開発だけがすべてではありません。開発の前段階の要求の洗い出し、リリース後の運用、さらに、フィードバックを受けての次段階の検討まで含めたライフサイクルの管理が必要です。この考え方に対して、ここ数年で、ALM(Application Lifecycle Management)という呼び名も生まれました。

ビジネスにかかわる関係各者

開発チームからビジネス全体へという話をもう少し掘り下げてみましょう。

プロジェクトが大きくなればなるほど分業化が進むわけですが、以下のようなポジションに分かれることになります。

  • 統制
    • 意思決定者です
    • 何を作る、何を優先する、何にどれだけのお金を投資するなどの最終判断を下します
    • 受託開発の場合だと、顧客との折衝なども含まれます
  • 開発
    • アプリ開発も、いろいろな人員の協業で成り立っています
    • (狭義に)開発
    • 実際にアプリを設計し、コーディングします
    • 進行管理
      • チーム内の開発状況に遅れがないか、あるなら解決方法は何かなど、チームの進行状況の管理や他チーム/統制との折衝を行います
    • テスト
      • 開発者本人のテスト記述では漏れるような第3者視点でのテスト、結合テスト、手動テストなどを行います
    • UX(ユーザー体験)デザイン
      • 人文科学的視点や、美術的な視点からアプリの操作性や外観を設計します
  • 運用
    • アプリ公開後、継続的にサーバーの管理や不具合報告、エンド ユーザーからのフィードバック受け付けなどを行います

 

個別の視点、個々人の戦術的な視点だけではプロジェクトは成功しません。全体を戦略的に眺める視点が必要です。

広い範囲全体を眺めるというのは、言うほどたやすいことではありません。ソフトウェア開発に対する要求が高度化するにつれ、この全体の把握を補助するツールの存在が重要になっています。

TFS

チーム全体の共同作業を支援するため、(クライアント アプリである)Visual Studioの他に、サーバー製品も提供されています。それが、TFS(Team Foundation Server)です。

Visual Studioとの連携(Visual Studio上からのソースコードや作業項目管理)に加えて、SharePointベースの管理ポータル ウェブ サイトを持っています。

今後は、Azure上に構築され、オン デマンドに使えるクラウド版TFS、Team Foundation Serviceも提供される予定です(現在、招待性のベータ版)。

Visual Studio 2010/TFSの機能

現状のVisual Studioが持っている機能を簡単に紹介しておきましょう。「ビジネス全体」の視点の機能は現在も拡充途中で、次期バージョンでもいろいろと新機能が入る予定です。

コーディング

  • コードの補完
  • リアルタイムなビルド/エラー検知
  • コードの構文ハイライト
  • 検索
  • リファクタリング
    • メソッド化、フィールドからプロパティの生成、変数/メンバー名変更
  • メンバー生成
    • 先にメソッドなどを使う側のコードを書いて、そこから未実装のメンバーを作る

デバッグ

  • ステップ実行
    • 1行ずつ実行しながら、変数の状態などの変化を見る
  • ブレイク ポイント
    • 特定の行を通った時に1度実行を止める
  • デバッグ情報の履歴保持(IntelliTrace)
    • デバッグ実行時の状態変化の履歴を、チーム内の別の誰かにそのまま渡して再現する機能

コード分析

  • メトリック(metric: 測定基準、数値化した指標)計算
    • バグを起こしがちなソースコードを判定するための指標を出す
  • プロファイリング
    • 性能分析

テスト

  • 単体テストの生成
  • テストの選択的実行
    • 現在カーソルのあるメソッドに関連する部分だけとか、修正した部分だけとか
  • テストの自動実行
    • TFS上で、ソースコードのコミット直後や、所定の時間にテストを実行
    • テストに通っていないコードをソースコード管理サーバーに反映させないということも可能
  • 多環境テスト
    • 仮想マシン上にいろいろな環境を構築して、その上でのテスト実行
  • 手動テストの作業項目管理/バグ レポート
  • UIの自動テスト
  • 負荷テスト

進捗管理

  • 作業項目管理
  • 状況の可視化
    • 作業項目の消化度合い
    • 残りのバグ数
    • 各種メトリック

補足

 

失敗の教科書

教科書的なプロジェクト管理/評価指標や、ツールによるその補助を軽視していませんか?

「これをやれば成功する」なんてものがないのは明白です。そんなのがあればみんなやります。しかし、「ここを外したら失敗する」みたいなものは、結構あります。教科書は、「成功するためのもの」ではなくても、「失敗しないためのもの」ではありえます。それをおろそかにして、失敗していませんか?

Visual Studioは、Premium版以上を買うと、様々なメトリックを計算して出してくれます。これもその「失敗しないためのもの」の一種です。数字を良くすればプロジェクトが成功するというものではないですが、数字が悪いほどプロジェクト失敗の確率が上がります。

統計的な研究あり

各種メトリックと、プロジェクトの欠陥に関する統計的な研究も、Microsoft Researchから出ていたりします。

ここでは、プロジェクトの欠陥の指標として、「リリース後に発見されたバグの数」と各種メトリックの適合率を求めているようです。Visual Studioが計算してくれるようなコードがらみのメトリックとは、大まかに、70~80%くらいの適合率が出ているようです。

そして、実は、組織的なメトリック(何社かかわっているかとか、チーム内のエンジニアの人数とか、ちょっとだけかかわって辞めていったエンジニアの人数とか)の方が重要で、コードがらみのメトリックよりもプロジェクト欠陥との適合率が高い(85%程度)という報告もあります。

また、地理的な距離よりも、組織的な距離の方が如実に欠陥に現れるそうです。何kmも離れた場所にいる同社同僚の方が、すぐ隣の他社出向社員よりも、心理的には「近い」とか。

マイクロソフト内の開発プロセス

マイクロソフトは、社内の開発プロセスがどういう風になっているかもオープンにしていたりします。

 

マイクロソフトでは、例えばVisual Studioという製品だけを取ってみても3500人以上の人間が開発にかかわっています。これだけの人数を一括して管理できるわけはなくて、以下のような分散管理になっています。

  • 10人程度のチームに分かれています
    • 進行管理1名、開発5名以下、テスト5名以下
  • 開発手法はそれぞれのチームが自由にやっていい。ただし、
    • 報告を義務付け
    • コミット前にクオリティ チェックがある

そして、分散した開発状況全体を把握するために、TFSの可視化機能が使われています。また、開発とテストの比率がほぼ1対1なことも注目に値するでしょう。

単体テスト

22 12月

プログラミング始めたての初心者、特に学生さんが相手だったりする場合、いつもこう言っています:

Visual Studio、まずは無料版のExpressでいいですよ。商用利用も可能です。C#に関していうと、コンパイラーの性能制限みたいなのもないです。

 

さて、じゃあ、こんな疑問も浮かぶかと思います:

なんで有償版があるの?それでなんでみんなProfessionalを買うの?

 

その答えの1つが、今日お話しする単体テストです。ということで、今日のお話は、Express版では試せなかったり…。逆に、普段からProfessionalよりも上のグレードを使いこなしてる人には少し退屈かも。

下準備: 今回のテスト対象

今日はベタに、簡単な計算をするメソッドを作って、それの単体テストをしてみましょう。

とりあえず、物自体(つまり、テストの対象)を作ります。UIも何もなし、ライブラリだけ作りましょう。名前は、取り合えず、適当にMyMathとかつけておきます。

 

プロジェクトを作ると、Class1.csというファイルができていると思います。まず、こいつをCalculator.csにリネームしてください。

ソリューション エクスプローラーでリネームすると、ファイル名だけじゃなく、中のクラスもClass1からCalculatorに変わるはずです。

まあ、簡単な例ということで、ただ単に足し算するだけのAddメソッドでも作ってみましょうか。Calculatorクラス内に、以下のようなコードを追加してください。

public static int Add(int x, int y)
{
    return x + y;
}

 

テスト プロジェクト/テスト メソッドを作ってみよう

そして、このAddメソッドを右クリック。コンテキスト メニュー内に、「単体テストの作成」というのがあるので、これをクリックしてください。

以下のようなダイアログ画面が出てくるので、OKを押しましょう。

初回は、「テスト用のプロジェクトを作りますか?」みたいなメッセージが出てくるはずなので、適当な名前を付けて「はい」を押してください。今回は、手抜きもいいところですが、デフォルトでつく名前、TestProject1のままで行きます。

 

以下のようなテスト用メソッドができてるはずです。

[TestMethod()]
public void AddTest()
{
    int x = 0; // TODO: 
適切な値に初期化してください
    int y = 0; // TODO: 
適切な値に初期化してください
    int expected = 0; // TODO: 
適切な値に初期化してください
    int actual;
    actual = Calculator.Add(x, y);
    Assert.AreEqual(expected, actual);
    Assert.Inconclusive(
このテストメソッドの正確性を確認します。);
}

テストになるように、中身を書き換えます。まあ、例えば以下のような感じ。

[TestMethod()]
public void AddTest()
{
    Assert.AreEqual(3, Calculator.Add(1, 2));
// 
本当のテストでは、もっとバリエーション持たせましょうね
}

テストで満たすべき条件を、Assertクラスの各種メソッドを使って書いていきます。この例の場合は、AreEqual、つまり、第1引数と第2引数の値が一致していないといけないという条件です。

テストを走らせてみよう

まあ、この例程度ならテストが通って当然ではありますが… なんにしても、本当にテストが通るか、確認してみましょう。

メニューから[テスト]→[実行]→[ソリューションのすべてのテスト]を選ぶか、Cntrl+R, Aとショートカット キーを押してください。

今回は単純なテストが1個だけなので、一瞬でテストが終わると思います。「テスト結果」ウィンドウが現れます。

成功です!

こまめにテストを走らせると、安心してコードを書き換えられます。

Test First

さて、こんな話もあります: テストを先に書け。

「テストがない」という状況を根絶するための工夫です。

実践してみましょう。まず、テスト クラス内(先ほどのAddTestメソッドの下にでも)に、以下のようなメソッドを追加してください。

[TestMethod()]
public void GcdTest()
{
    var testData = new[]
    {
        new { X = 100, Y = 15, Z = 5 },
        new { X = 144, Y = 81, Z = 9 },
        new { X = 13*11*4, Y = 13*9*5, Z = 13 },
        new { X = 1024, Y = 999*2, Z = 2 },
        new { X = 13*11, Y = 9*8, Z = 1 },
        new { X = 360, Y = 80, Z = 40 },
        new { X = 10, Y = 10, Z = 10 },
    };

    foreach (var item in testData)
    {
        Assert.AreEqual(item.Z, Calculator.Gcd(item.X, item.Y));
        Assert.AreEqual(item.Z, Calculator.Gcd(item.Y, item.X));
    }
}

最大公約数(greatest common divisor、略してGCD)を求める想定で、先にテストだけ書きました。この時点では、まだGcdメソッドも作っていないです。

メソッドがないので当然エラーになるわけですが、Visual Studioを使っていると、エラー個所に以下のようなスマート タグが現れるはずです。

この「メソッド スタブを生成します」を選んでみましょう。Calculatorクラス内に、以下のようなメソッドが自動生成されます。

public static object Gcd(int p, int p_2)
{
    throw new NotImplementedException();
}

じゃあ、実装しましょうか、最大公約数。以下の通り。戻り値の型も、objectからintに変えておきましょう。

public static int Gcd(int x, int y)
{
    while (true)
    {
        var r = x % y;
        if (r == 0) return y;
        x = y;
        y = r;
    }
}

再びテストを実行して、成功を確認しましょう。

Expressの場合: せめてテスト用のコンソール アプリを

この、Visual Studio組み込みの単体テストのいいところは、

  • どの範囲のテストを実行するか選んだりもできる
    • 今、エディター上でカーソルのあるメソッドのテストだけ実行するとか
    • 前回失敗したところだけ実行とかも
  • チーム開発機能と組み合わせて、テストに通ったソース コードしか、管理サーバーにコミット(commit: 約束する、制約する。この場合、「ちゃんとできたから責任もってサーバーに反映するね」という意味)できないようにできる

等々あります。

 

まあ、そこまでやらずとも、とりあえずテスト コードを書くだけなら、適当にコンソール アプリでも作って、そこにテストを書けば大丈夫です。この方法なら、Visual C# Expressでもテストが書けます。

NUnit

ちなみに、NUnitという、オープンソースな単体テスト フレームワークもあって、こいつはExpress版にも対応しているそうなので、ぜひとも導入を検討してみてください。

privateメンバーのテスト

さて、privateなメンバーのテストはどうしましょう?プログラミング言語によっては、「privateだとテストできなくなるし、全部publicで作ればいいんじゃない?」なんていう人もいるみたいです。

が、Visual Studioではそんな心配不要です。Visual Studioが、リフレクションを使ってprivateメンバーに無理やりアクセスするAccessorクラスというのを作ってくれます。

例えば、Calculatorクラスに以下のようなメソッドを追加してみましょう。

private static int PrivateMul(int x, int y)
{
    return x * y;
}

こいつを、右クリックして「単体テストの作成」すると、以下のようなテスト メソッド(と、Accessor)が作られます。

[TestMethod()]
[DeploymentItem(“MyMath.dll”)]
public void PrivateMulTest()
{
    int x = 0; // TODO: 
適切な値に初期化してください
    int y = 0; // TODO: 
適切な値に初期化してください
    int expected = 0; // TODO: 
適切な値に初期化してください
    int actual;
    actual = Calculator_Accessor.PrivateMul(x, y);
    Assert.AreEqual(expected, actual);
    Assert.Inconclusive(
このテストメソッドの正確性を確認します。);
}

Calculator_Accessorというクラスが自動生成されていて、こいつは、Calculatorのprivateメンバーを、リフレクションを使って無理やりpublicにアクセスできるようにしたものです。

便利ツール

最後に、単体テストで使える便利ツールを紹介しておきましょう。

Pex

メソッドの中身に応じてテスト コードを生成してくれるVisual Studioアドインです。テスト漏れが起きないように、きわどいケースなんかを生成してくれます。

(メソッドの中身を気にせず、仕様を元に「このメソッドはこうあるべき」みたいなテストを書くことをブラック ボックス テストと言います。一方、Pexのように、中身を想定して、はまりがちなテスト ケースを書くことをホワイト ボックス テストと言います。)

Moles

Pexの付属品なんですが、標準ライブラリ内のメソッドを自作のものに置き換えてしまう機能を提供するツールです。

例えば、DateTime.Nowのような、常に違う値を返すメソッドを、所望の値を返すように書き換えてしまうというような使い方ができます。

Moq

動的処理の回で書きましたが、テストのお供にモック(mock: 模造品)生成フレームワークがあります。

代表例はMoqなどです。