Tips: interface と partial class で横断的関心事を分離
※ C# Advent Calendar 2016 の12月23日の記事。
- 前の日の記事:
- 次の日の記事: Material Design In XAML Toolkit で WPF アプリにモダンな UI を! | Qiita
以前、「C# Tips: interface を 抽象クラス (abstract class) とどう使い分けるか」という記事を書いた。 その中で、「アスペクトの実装を便宜上 (言語の都合上) interface で行う」というイディオムについて触れた。 この記事はその続きだ。 より具体的にこのイディオムを紹介する。
分割攻略と疎結合/高凝集
ソフトウェア開発というものは往々にして複雑さとの戦いになるものだが、プログラムの設計において複雑さに立ち向かうための基礎となる考え方に、分割攻略 (Divide and Conquer、分割統治) というものがある。 大きく複雑な問題をそのまま解くのは大変なので、より小さくシンプルな問題に分けることで、全体としての複雑さを下げて解こう、という戦略だ。
上の図のようにすると大変なので、たとえば次のようにする。 10倍の大きさの問題の複雑さは10倍ではきかない、というのが基本的なアイディアだ。
分割するときに重要となるのが、「どう分けるか」だ。 一般的には次のようになれば良いとされている。
- 疎結合 (low coupling): 分割されたもの同士の結び付きを少なく/弱く・
- 高凝集 (high cohesion): 一つの分割単位の中が一つの関心事だけになり、かつ、その関心事がその分割単位の中だけにある
ソフトウェアの設計では、疎結合で高凝集になるように分割することが大切、ということだ。 いくら小さな単位に分けても、問題が互いにからみあっていたり、シンプルな単位に分かれていなかったりすると、うまく複雑さが減ってくれないからだ。
そして、これを実現するために、様々な設計の考え方がある。 オブジェクト指向という考え方を使っても、ある程度これを行うことができる。 オブジェクト指向では、クラスやオブジェクトなどという単位に分けることでこれを行うわけだ。
オブジェクト指向と横断的関心事
最初の CAD の設計
ところが、オブジェクト指向といっても万能なわけではなく、クラスやオブジェクトなどに分けるというだけでは、必ずしも高凝集にならない。
例をみてみよう。 以下は、C# による CAD (Computer-Aided Design) の設計の例だ。
図の中の赤いクラスがモデル (Model) で、抽象図形クラス Figure と、そこから継承した複数の具象図形クラス LineFigure・EllipseFigure がある。
青いクラスがビュー (View) で、モデルの IEnumerable<Figure> というインタフェイスを使ってモデルとデータバインドし、個々の図形を描画する。
C# によるソース コードは、たとえば次のようなものになる (説明に必要のない部分は省略)。
MiniCad.cs
using System; using System.Collections; using System.Collections.Generic; abstract class Figure { public abstract void Draw(); } class LineFigure : Figure { public override void Draw() => Console.WriteLine("Line!"); // 仮実装 } class EllipseFigure : Figure { public override void Draw() => Console.WriteLine("Ellipse!"); // 仮実装 } class CadModel : IEnumerable<Figure> { public IEnumerator<Figure> GetEnumerator() { yield return new LineFigure (); yield return new LineFigure (); yield return new EllipseFigure(); yield return new LineFigure (); } IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } class CadView { public IEnumerable<Figure> DataSource { set { value.ForEach(figure => figure.Draw()); } } } class Program { static void Main() { new CadView().DataSource = new CadModel(); } } static class EnumerableExtensions { public static void ForEach<TElement>(this IEnumerable<TElement> @this, Action<TElement> action) { foreach (var element in @this) action(element); } }
この実装では仮にコンソールに文字列を出力しているだけなので、実行結果は次のようになる。
Line! Line! Ellipse! Line!
この段階ではまだ単純な設計であるため、オブジェクト指向を使うことでそこそこ高凝集になっている。
CAD の設計の変更
さて、ここまで作った後で、ファイルなどに保存するときのためにシリアライズ機能を付けたくなったとする。 CAD は一般的に様々なフォーマットをサポートすることが多いものだが、ここでは仮に SVG (Scalable Vector Graphics) 形式と独自のバイナリ―形式をサポートするものとしよう。
このために、それぞれの図形クラスに、2つの形式のシリアライズのための SvgSerialize と BinarySerialize という2つのメソッドを追加してみるとどうなるだろうか。
C# によるソース コードは、たとえば次のように変わるだろう。
MiniCad.cs
using System; using System.Collections; using System.Collections.Generic; abstract class Figure { public abstract void Draw(); public abstract void SvgSerialize(); public abstract void BinarySerialize(); } class LineFigure : Figure { public override void Draw() => Console.WriteLine("Line!"); // 仮実装 public override void SvgSerialize() => Console.WriteLine("SvgSerialize line!"); // 仮実装 public override void BinarySerialize() => Console.WriteLine("BinarySerialize line!"); // 仮実装 } class EllipseFigure : Figure { public override void Draw() => Console.WriteLine("Ellipse!"); // 仮実装 public override void SvgSerialize() => Console.WriteLine("SvgSerialize ellipse!"); // 仮実装 public override void BinarySerialize() => Console.WriteLine("BinarySerialize ellipse!"); // 仮実装 } class CadModel : IEnumerable<Figure> { public void SvgSerialize() => this.ForEach(figure => figure.SvgSerialize()); public void BinarySerialize() => this.ForEach(figure => figure.BinarySerialize()); public IEnumerator<Figure> GetEnumerator() { yield return new LineFigure (); yield return new LineFigure (); yield return new EllipseFigure(); yield return new LineFigure (); } IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } class CadView { public IEnumerable<Figure> DataSource { set { value.ForEach(figure => figure.Draw()); } } } class Program { static void Main() { var model = new CadModel(); new CadView().DataSource = model; model.SvgSerialize (); model.BinarySerialize(); } } static class EnumerableExtensions { public static void ForEach<TElement>(this IEnumerable<TElement> @this, Action<TElement> action) { foreach (var element in @this) action(element); } }
そして、これが実行結果だ。
Line! Line! Ellipse! Line! SvgSerialize line! SvgSerialize line! SvgSerialize ellipse! SvgSerialize line! BinarySerialize line! BinarySerialize line! BinarySerialize ellipse! BinarySerialize line!
しかし、この設計では、高凝集になっていない部分がでてきてしまっているのがお分かりだろうか。
図形クラスという部分に関しては、ある程度高凝集になっている。 各図形に関する仕事 (それぞれの図形の描画やシリアライズ) は、ちゃんと各図形でやっているように見える。
ところが、SVG シリアライズ、あるいはバイナリー シリアライズという関心事に目を向けてみると、そちらはどうなっているだろう。
たとえば、SVG シリアライズに関するメソッドは Figure、LineFigure、EllipseFigure、CadModel という複数のクラスにまたがってしまっている。 バイナリー シリアライズについても同様だ。 これでは、高凝集、すなわち「一つの分割単位の中が一つの関心事だけになり、かつ、その関心事がその分割単位の中だけにある」とは言えないだろう。
このように、オブジェクト指向では複数のクラスをまたがる関心事というものがでてきて設計に困ることがある。 この場合だと、それぞれの図形への関心事とシリアライズという関心事が直交してしまっている。 そのため、一方の視点での分割によるかたまりが、他方の視点での分割をまたがってしてしまうのだ。 このような関心事は、横断的関心事 (crosscutting concern) と呼ばれる。
この例では、はじめは図形のクラス設計を行っていて、後からSVG シリアライズやバイナリー シリアライズといった横断的関心事がでてきてしまったのだ。
interface と partial class で横断的関心事を分離
なんとか、それまでのクラスの設計をこわすことなく、この横断的関心事を分離できないものだろうか。
この記事では、C# の interface と partial class を使ったイディオムをご紹介したい。
先のコードのようにいきなりシリアライズが必要なそれぞれのクラスの中に SvgSerialize メソッドと BinarySerialize メソッドを追加するのではなく、先ず partial class とだけしてみる。
MiniCad.cs
using System; using System.Collections; using System.Collections.Generic; abstract partial class Figure { public abstract void Draw(); } partial class LineFigure : Figure { public override void Draw() => Console.WriteLine("Line!"); // 仮実装 } partial class EllipseFigure : Figure { public override void Draw() => Console.WriteLine("Ellipse!"); // 仮実装 } partial class CadModel : IEnumerable<Figure> { public IEnumerator<Figure> GetEnumerator() { yield return new LineFigure (); yield return new LineFigure (); yield return new EllipseFigure(); yield return new LineFigure (); } IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } class CadView { public IEnumerable<Figure> DataSource { set { value.ForEach(figure => figure.Draw()); } } } class Program { static void Main() { var model = new CadModel(); new CadView().DataSource = model; model.SvgSerialize (); model.BinarySerialize(); } } static class EnumerableExtensions { public static void ForEach<TElement>(this IEnumerable<TElement> @this, Action<TElement> action) { foreach (var element in @this) action(element); } }
この Main メソッドでは、SvgSerialize メソッドを BinarySerialize メソッドを使っているが、この時点ではどこにも実装がない。
次に、SvgSerialize メソッドを持つという interface である ISvgSerializable を作り、それを各モデル クラスで実装する。そして、 この実装を partial class の機能を用いて別ファイルで行うことにする。 こんな具合だ。
ISvgSerializable.cs
using System; interface ISvgSerializable { void SvgSerialize(); } partial class Figure : ISvgSerializable { public abstract void SvgSerialize(); } partial class LineFigure { public override void SvgSerialize() => Console.WriteLine("SvgSerialize line!"); // 仮実装 } partial class EllipseFigure { public override void SvgSerialize() => Console.WriteLine("SvgSerialize ellipse!"); // 仮実装 } partial class CadModel : ISvgSerializable { public void SvgSerialize() => this.ForEach(figure => figure.SvgSerialize()); }
こうすると、SVG シリアライズという責務を記述するコードがすべてこのファイルに集まることになる。
BinarySerialize メソッドの方も、同様に別ファイルを用意する。 そこで IBinarySerializable という interface を作り、それを各モデル クラスで実装する。
IBinarySerializable.cs
using System; interface IBinarySerializable { void BinarySerialize(); } partial class Figure : IBinarySerializable { public abstract void BinarySerialize(); } partial class LineFigure { public override void BinarySerialize() => Console.WriteLine("BinarySerialize line!"); // 仮実装 } partial class EllipseFigure { public override void BinarySerialize() => Console.WriteLine("BinarySerialize ellipse!"); // 仮実装 } partial class CadModel : IBinarySerializable { public void BinarySerialize() => this.ForEach(figure => figure.BinarySerialize()); }
実行結果は変わらない。 クラス図も ISvgSerializable と IBinarySerializable という2つのインタフェイスが加わっただけだ。
これは、オブジェクト指向で横断的関心事を分離したわけではない。 オブジェクト指向にも限界がある。 ここでは、横断的関心事をクラスにマッピングすることではうまく分離できなかった。
そのため、ここでは C# の機能を使い、それまでの関心事に直交した新たな関心事をファイルにマッピングすることで分離した、ということだ。
Visual Studio 2017 のライブ ユニット テスト機能による「車窓からの TDD」
※ Visual Studio Advent Calendar 2016 の12月16日の記事。
コーディング機能やデバッグやテストの機能が大幅パワーアップ! 次期バージョン「Visual Studio 2017 RC」 | CodeZine という記事を書かせていただき、その中で、「Visual Studio 2017 RC」の「特におすすめの新機能」としてライブ ユニット テストに触れた。 もう少し具体的にライブ ユニット テストを紹介してみたい。
題材として、『ソフトウェア技術者サミット in 福井 2016』 (7月16日) の「テスト駆動開発ライブ 〜C#ペアプログラミング実況中継」というセッションの中で、平鍋健児氏と C# と Visual Studio 2015 を使っておこなったテスト駆動開発 (Test-Diven Development: TDD) のデモンストレーションを用いることにする。
このデモンストレーションは、北野弘治氏と平鍋健児氏による「車窓からの TDD | オブジェクト倶楽部」 を C# で再現したものだ。 テストを書きながら、スタックのクラスを作成していく。 順を追ってやってみよう。
プロジェクトの作成
最初に、Visual Studio 2017 RC を起動し、テストするプロジェクトとテストされるプロジェクトを作る。
- テストされるプロジェクトの作成
- ソリューション エクスプローラでソリューション名を右クリックし、「追加 > 新しいプロジェクト > Visual C# > クラス ライブラリ (.NET Framework) Visual C#」
ライブ ユニット テストの開始
では、早速 Visual Studio 2017 の新機能であるライブ ユニット テストを開始しよう。 次のようにメニューから選ぶだけだ。
- メニュー > テスト > Live Unit Testing > Start
最初のテスト
それでは、単体テスト プロジェクトに最初のテストを追加してみよう。 TDD では、テストされるコードよりテスト コードを先に書くことが多い。
最初のテスト: 「作ったら空」
using Microsoft.VisualStudio.TestTools.UnitTesting; namespace Shos.Collections.Test { [TestClass] public class Stackのテスト { [TestMethod] public void 作ったら空() { var stack = new Stack<int>(); Assert.IsTrue(stack.IsEmpty); } } }
クラス名を「Stackのテスト」とし、「作ったら空」というテストを追加した。 まだ Stack クラスは作っていないので、静的なエラー (コンパイル時エラー) になり、エラー箇所に赤い波線が表示される。
バルブ アイコンをクリックするか、エラー箇所にカーソルがある状態で 'Ctrl+.' をタイプし、クラス ライブラリ プロジェクトの方に Stack クラスを作成しよう。
OK ボタンを押すと、クラス ライブラリ プロジェクトに Stack クラスが生成される。
生成された Stack クラス
namespace Shos.Collections { public class Stack<T> { public Stack() { } } }
テストの方では、まだ "stack.IsEmpty" の部分が静的エラーになっている。
バブル アイコンまたは 'Ctrl+.' から「プロパティ 'Stack.IsEmpty' を生成します」を選ぼう。
Stack クラスに、プロパティ "IsEmpty" が生成される。 このように、Visual Studio の助けを借りることで、スムーズに TDD を行うことができる。
ライブ ユニット テスト
"IsEmpty" が作られたことで、で静的エラーが消えた。
すると、ここでライブ ユニット テスト機能が自動で働く。 テストする側のクラス「Stackのテスト」の左に、テストが失敗したことを示す赤い×印が表示される。
そして、テストされる側のクラス Stack の左にも、テストが失敗したことを示す赤い×印があらわれる。
では、テストを成功させるために、Stack クラスを修正しよう。 テスト コード中の "IsEmpty" にカーソルがある状態で 'F12' を押す (または、"IsEmpty" を右クリックして「定義に移動」)。
ここでは、"IsEmpty" の実装を "public bool IsEmpty => true;" に変更してみる。
そうすると、ライブ ユニット テストによって自動でテストが通り、Stack クラスと「Stackのテスト」クラスに表示されていた赤い×印が緑のチェックに変わる。
このように TDD では、次のようなステップで踏み、それを繰り返しながら、プログラミングを進めていく。
- テストを書く
- (コンパイラーによる静的エラー – 静的なテスト)
- テストされる側のコードを書き、テストを失敗させる (ライブ ユニット テストによる動的エラー – 動的なテスト – レッド)
- テストを成功させる分だけテストされる側のコードを修正し、テストを成功させる (グリーン)
- 1 に戻る
テストされる側にコードを追加する場合は、テストを追加し一度テストを失敗させる。 そして、テストが通る分だけのコードをテストされる側に追加する。
テストによってコードのその時点でのあるべき姿を記述する。 つまり、メソッドなりクラスなりの外からみた仕様をテストで先に記述するわけだ。 このテストが通ったことをもって、コードがあるべき姿になったことにする。 これを繰り返すことで、あるべき姿を少しずつインクリメンタルに作っていくのだ。 メソッドやクラスが、その時点でのあるべき姿になったかどうかが、テストによってフィードバックされる。
そして、Visual Studio 2017 のライブ ユニット テスト機能を使えば、このフィードバックがリアルタイムに行われることになるのだ。 仕様を満たしていないコードがレッドで、仕様を満たしたコードがグリーンで、リアルタイムで可視化される。 とても効率の良いコーディング環境だ。
テスト「Pushしたら空じゃなくなる」の追加
さて、テストを追加してみよう。
using Microsoft.VisualStudio.TestTools.UnitTesting; namespace Shos.Collections.Test { [TestClass] public class Stackのテスト { Stack<int> stack; [TestInitialize] public void 準備() => stack = new Stack<int>(); [TestMethod] public void 作ったら空() { Assert.IsTrue(stack.IsEmpty); } [TestMethod] public void Pushしたら空じゃなくなる() { stack.Push(1); Assert.IsFalse(stack.IsEmpty); } } }
"stack = new Stack<int>()" のコードが重複するのが嫌なので、"[TestInitialize] public void 準備() => stack = new Stack<int>();" というコードを追加した。 このメソッドは、個々のテストの実行前に一回ずつ呼ばれる。 この部分は、まだテストされていないが、このようなコードの左には、青い横棒が表示される。 テストしていないコードが可視化されるわけだ。 これにより、常にカバレッジが確認できる。
テストを追加した直後は、"stack.Push(1)" の "Push" が静的エラーになる。 Stack.Push メソッドがまだないためだ。 バブル アイコンまたは 'Ctrl+.' から「メソッド 'Stack.Push' を生成します」を選ぼう。 また動的テストが自動で走り、ちゃんと失敗する。
テストが通るように Stack クラスの Push メソッドを修正しよう。 テスト コード中の "Push" にカーソルがある状態で 'F12' を押す (または、"Push" を右クリックして「定義に移動」)。 "public void Push(int v) { throw new NotImplementedException(); }" の左には赤い×印が表示されているはずだ。
Stack クラスを、例えば次のように変更すると、テストが通って、緑のチェックに変わる。
TDD のリズム
ではまた、テストを追加しよう。 静的エラーになる (赤い波線)。
'Ctrl+.' から「プロパティ 'Stack.Top' を生成します」を選択。 また動的テストが自動で走り、ちゃんと失敗 (赤い×印)。
'F12' を押して、Stack クラスを修正。 また動的テストが自動で走って成功 (緑のチェック)。
今度は、テスト「PushせずにTopをみたら例外」の追加。失敗。
Stack クラスを修正するとテストが成功。
TDD ではレッドとグリーンの繰り返しのリズムが大切だと思う。 テストのための無駄な作業を省いてくれるライブ ユニット テスト機能が、このリズムを心地よいものにし、プログラミングをより楽しくしてくれることだろう。
この例では、なるべく小さなステップで進めるようにしているので、テストが通る最小限の修正にとどめているが、コードが明らかであるような場合は、もっと大きな修正をしても構わないだろう。
リファクタリングについて
今回は出てきていないが、TDD では、テストが通った後にリファクタリング (外から見た仕様を変えずに内部構造を改善すること) を行うことが多い。Visual Studio 2017 のライブ ユニット テスト機能を使うと、このリファクタリングの際も常に自動で静的テストと動的テストによって、仕様どおりであり続けていることがチェックされることになる。 リファクタリング中に誤ってバグを作ってしまってもすぐに気付けることだろう。
リファクタリングでは、なるべくエラーが起きている時間を短くすることが肝要だが、こうしたエラーの可視化によるフィードバックが常に起こることは、エラー時間の最小化につながるだろう。
また、リファクタリング中の継続的なフィードバックによって、なるべくレッドにならないような手順でリファクタリングをするような良い習慣が生まれるのではないだろうか。
もちろん、Visual Studio 2017 で追加された多くの新たなリファクタリング機能も安全なリファクタリングに役立ってくれることだろう。
まとめ
Visual Studio 2017 RC の新たな機能であるライブ ユニット テストは、機能を使うことに手間を取られない。 機能を使うことに振り回されて、コーディングのリズムを狂わされることがない。 つまり、Visual Studio 2017 RC を使うと TDD が楽しく快適になる。
Microsoft MVP を再受賞しました (My 12th MVP Award from Microsoft)
Microsoft MVP Award を再受賞しました。12年目になります。
- Microsoft MVP for Development Tools - Visual C# (Jul. 2005 - Dec. 2014)
- Microsoft MVP for .NET (Jan. 2015 - Oct. 2015)
- Microsoft MVP for Visual Studio and Development Technologies (Nov. 2015 - Jun. 2017)
いくつになっても、こうして褒められるのは嬉しいものです。 マイクロソフトのような大企業が本気で褒めてくれる。ありがたいことです。
沢山の素晴らしい方々と出会える機会をいただいております。 お世話になっている皆様に感謝です。いつもありがとうございます。
『ソフトウェア技術者サミット in 福井 2016』 (2016年7月16日)が開催されます
『ソフトウェア技術者サミット in 福井 2016』
~ITアーキテクトの第一人者に聞く! 福井で一流のエンジニアになる方法~
日本を代表するITアーキテクトの皆さんに、福井で語っていただきます!
一緒に福井で一流のソフトウェア エンジニアになる方法を学びましょう。
学生さん、新人さん、大歓迎です。
どうぞご参加ください。
■ 日時:
2016-07-16(土)13:00 - 18:30
■ 会場:
福井大学 文京キャンパス
総合研究棟VII (工学3号館 / 情報・メディア工学科) 311L講義室
福井県福井市文京3丁目9番1号
■ 主催/協力:
■ お申込み:
https://fitea.doorkeeper.jp/events/45122
■ 参考サイト:
- 前々回『ソフトウェア技術者サミット in 福井』(2005/01/31)
- 前回『ソフトウェア技術者サミット in 福井 2007』(2007/01/12)
■ イベント チラシ:
Build 2016 2日目の発表内容まとめ
※ 「Build 2016 1日目の発表内容まとめ」の続き。
2日目のキーノートに関する記事。
- //build/ 2016 Day 2 Keynote | ブチザッキ
- //build/ 2016 Day 2 リンクとか Azure Update とか (2016.04.01) | ブチザッキ
- マイクロソフト、あらゆる開発者向けのクラウドサービス、開発ツール、プロダクティビティの拡張機能を発表 | News Center Japan Edit | Microsoft
2日目の発表内容は以下の通りだ。
1. Xamarin が Visual Studio に
マイクロソフトが買収した Xamarin (C# を使って iOS や Android などのネイティブ アプリが作れるツール) が、Visual Studio に含まれることになった。
Visual Studio の Enterprise エディションや Professional エディションの他、無償版の Community エディションでも追加料金なしで使うことができるようになる。
- [速報] Visual Studioに無料でXamarinが追加。無料のCommunity EditionでもiOS/Androidネイティブアプリが開発可能に。Build 2016 | Publickey
- 【速報】Xamarin のこれからについて! | Xamarin 日本語情報
- Microsoft、マルチプラットフォームアプリ開発ツール「Xamarin」を無償に | ITmedia ニュース
- MS、「Xamarin」を「Visual Studio」に組み込み無料提供へ--コア技術をオープンソース化 | CNET Japan
- Xamarin for Everyone | Xamarin Blog (英語)
- Mobile App Development made easy with Visual Studio and Xamarin | The Visual Studio Blog (英語)
2. Microsoft Azure 関連
- [速報] Microsoft Azureにもサーバレスアーキテクチャ、「Azure Functions」発表。ランタイムはオープンソース化。Build 2016 | Publickey
- コードはオープンソースで提供 : 米マイクロソフト、AWS Lambda的なサービス「Azure Functions」を発表 | @IT
3. その他
Build 2016 1日目の発表内容まとめ
マイクロソフトの最大の開発者向けイベント「Build 2016」がサンフランシスコで開催中。
Build 2016
内容は、一部ライブで観ることができる。
1日目に関する記事が、既にあちこちに上がっている。
1日目のキーノートに関する記事も沢山。
- //build/ 2016 Day 1 Keynote | ブチザッキ
- //Build/ 2016 Day1 メモ | ケンタテクブロ
- Microsoft Build 2016の基調講演(Day 1)まとめ | ITmedia ニュース
- MS「Build 2016」での主な発表内容まとめ--「HoloLens」は開発者向けに出荷 | ZDNet Japan
- Windows 10大幅アップデート、マイクロソフト開発者イベントBuild 2016が開催 | ASCII.jp
- 【イベントレポート】WindowsにUbuntuのBashがやってくる | PC Watch
- マイクロソフト、インテリジェント ビジョンの概要と Windows 10 の新たなイノベーションを発表 | News Center Japan | Microsoft
- マイクロソフト「Build 2016」ベスト&ワースト、一番の注目は発表されなかったこと | ギズモード・ジャパン
1日目の発表内容は以下の通りだ。
1. Windows 10 関連の発表
1.1. BashシェルをWindowsに搭載
Windows 10 で Linux のシェルのバイナリ―をそのまま動作できるようにするとのこと。
マイクロソフトは、最近 Windows 以外の OS との親和性をどんどんと高めており、その一環だろう。
- [速報] マイクロソフト、BashシェルをWindowsに搭載。Emacs、VT100などサポート。Build 2016 | Publickey
- Windows 10がBashに公式ネイティブ対応。マイクロソフトとカノニカルが協力、Ubuntu Linuxのコマンドラインツールがそのまま動作 | Engadget Japanese
- Build 2016で驚きの発表―Microsoftはこの夏Windows 10でBashシェルをサポート | TechCrunch Japan
- 開発者がWindows 10でBashシェルとユーザー モードのUbuntu Linuxバイナリを実行可能に | S/N Ratio (by SATO Naoki)
- 「Windows 10」でUbuntuのBashがネイティブ動作可能に | CNET Japan
- 「Windows 10」で動作するUbuntuのBashシェル--その実現方法 | ZDNet Japan
- Windows 10次期バージョンに搭載:米マイクロソフトがBash on Windowsを発表、その目的は | @IT
- どういうこと? UbuntuがWindows 10で動くよ | ギズモード・ジャパン
- 米MS、Windows 10上でUbuntuのユーザーモードを動作させ、Bashを利用可能に | CodeZine
- Windows で Ubuntu バイナリ(bash)が動作することの概略 | 蒼の王座・裏口
1.2. Windows 10 の大型アップデートについて
- Windows 10 初の大型アップデート「Anniversary Update」、今夏提供へ | ZDNet Japan
- Windows 10次期大型アップデート「Anniversary Update」は2016年夏に無償提供 | ITmedia PC USER
- Windows 10の2016年版アップデート「Anniversary Update」、今夏にリリースへ (Impress Watch) | Yahoo!ニュース
2. 「Microsoft Bot Framework」を公開
クラウド上の「マシン ラーニング」機能の応用としての「人工知能」関連だ。
最近マイクロソフトや Google、Amazon などが取り組んでいることで話題になっている。
- [速報] マイクロソフト、Bot開発用フレームワーク「Microsoft Bot Framework」を公開。Slack、Skype、メール、SMSなど対応。Build 2016 | Publickey
- Microsoft Bot Framework (英語)
3. Visual Studio 関連の発表
Visual Studio "15" Preview と Visual Studio 2015 Update 2 RTM が公開された。
- Visual Studio 2015 Update 2がRTM & Visual Studio "15" Preview | ++C++; // 未確認飛行 C ブログ
- Visual Studio "15" Preview | Release Notes (英語)
- Visual Studio "15" Previewリリース | Visual Studio 日本チーム Blog
- Visual Studio "15" Preview Downloads (英語)
- Visual Studio 2015 Update 2 RTM | The Visual Studio Blog (英語)
- Visual Studio 2015 Update 2 | Release Notes (英語)
- Visual Studio 2015 Update 2 リリース | Visual Studio 日本チーム Blog
- Visual Studio 2015 Update 2 RTM Downloads
Visual Studio 2015 Update 2 は「プログラムと機能」から Visual Studio 2015 の「変更」を選んでインストールするのが簡単だ。
また、MSDN からは Update 2 込みの Visual Studio 2015 がダウンロードできるようになっている。
4. その他
その他、以下のような発表があった。
4.1 Desktop App Converter
Win32/.NETアプリを UWP (*1) アプリに変換するツール。
(*1) UWP とは: ユニバーサル Windows プラットフォームの略。Windows 10 を積んだPC や Phone、XBox One、HoloLens、Surface Hub などで動作可能。
4.2 XBox Dev Mode
Visual Studio で XBox One 用に UWP アプリを開発可能に。Visual Studio からリモートデバッグもできる。
4.3 HoloLens 関連
開発者エディションを提供開始。
4.4 Cortana 関連
様々なアップデートがあったようだ。
4.5 .NET Framework 4.6.2 Preview
「C# 大好き MVP による、C# ドキドキ・ライブコーディング!!」でテトリス的なゲームを作った。(Hokuriku ComCamp 2016 - 2月20日)
※ 「[Event] 「Hokuriku ComCamp 2016 powered by MVPs」 (2016年2月20日)を開催しました」の続きです。
「Hokuriku ComCamp 2016 powered by MVPs」では、北信越の3人の Microsoft MVP (石野 光仁 さん、鈴木 孝明 さん、私) で毎年恒例/大好評の「C# 大好き MVP による、C# ドキドキ・ライブコーディング!!」というセッションを行いました。
セッションは、毎回石野 さんが考えてくださっています。 無茶ブリが楽しい素敵なセッションだと思います。
今回の石野さんからのお題は、「30分でテトリス ライクなゲームを作ろう!」というかなりチャレンジングなものでした。
「C# 大好き MVP による、C# ドキドキ・ライブコーディング!!」当日の様子
ライブ コーディングは毎回ドキドキものです。
交代で喋り、自分以外が喋っているときにコーディングさせてもらえる、という進行でした。
私の分の資料
私の作った部分について説明してみます。
私の分の資料を下記で公開しました (slideshare と Docs.com にそれぞれ)。
戦略やどのようにインチキ工夫したかを書いてみました。
私のテトリス ライクなゲームの構成
全体の構成は次のようになっています。
FTetris.Model | ビューから分離したモデル部分の C#/.NET 版です。他の .NET のプログラムから参照されるクラス ライブラリ (DLL) です。 | |
---|---|---|
FTetris.WPF | WPF (Windows Presentation Foundation) で作ったゲームです。C# で書かれています。View と ViewModel からなっており、上記 Model を参照しています。つまり、WPF の標準的な設計方法である MVVM (Model - View - ViewModel) アーキテクチャーで作られています。 | |
FTetris.WinForm | Windows Forms 版です。C# で書かれており、GDI+ で描画を行っています。セッション中のライブで主に作った部分です。 | |
FTetris.Console | コンソール アプリケーション版です。C# で書かれています。色がついています。 | |
FTetris.Matrix | セッションでモデルを説明するためだけに作った、映画マトリックスをイメージした緑色の数字が降ってくる版です。 | |
FTetris.Win | セッションで「インチキ」と称した、Windows Forms のメイン フォームに WebBrowser を貼って下記 TypeScript 版の URL を渡しただけの 1 分で作れる版です。 | |
FTetris.TS | 上の「インチキ」をやるために作っておいた Web アプリケーション版です。 TypeScript で書かれています。 モデル部分は、上の FTetris.Model から移植しました。 Three.js から WebGL を使っています。 Windows 以外の OS でも動作します (スマートフォンやタブレットでも動作可能ですが、操作にはキーボードが必要です)。 |
上記資料にも書きましたが、モデルを (WPF や Windows Forms、コンソール等の) ビューから分離しています。
ゲーム本体のロジックをモデルとして書くことで、ビュー側の実装に依存しない形にし、各プラットフォームで使えるようにしました。
FTetris.Model 等の設計
モデル部分の設計は次のようになりました。
このモデルは、先ず C# で実装し、それから TypeScript に移植しましたので、TypeScript 版もほぼ同じ設計です。
このモデルを使った例として、WPF 版の設計は次のようになりました。
MVVM (Model - View - ViewModel) になっています。
ソースコード
私の分の全体のソースコードは GitHub で公開しています。
TypeScript 版 (HTML/CSS + TypeScript + Three.js + WebGL)
TypeScript で書いた Web アプリケーション版は下のリンクから実際に遊ぶことができます。
くるくる回るようにしたので、通常のものよりだいぶ難しくなっています。
マウスのドラッグやホイールで視点 (カメラ位置) を変えられます。
キー操作
ゲームのキー操作は、どの版も共通で、次のようになっています。
キー | 動作 |
---|---|
← | 左移動 |
→ | 右移動 |
↑ | 回転 (時計回り) |
↓ | 回転 (反時計回り) |
Space | 落下 |
Enter | 最初からプレイ |
関連サイト
鈴木さんと石野さんも、ご自身の分のゲームを公開されています。
三者三様で興味深い内容です。
レポート
鈴木さんの記事はこちらです。
彼の作った部分について、アプリケーションやソースコード、戦略や設計なども公開されています。