.NETエンジニアのための定期勉強会(Sansan主催)レポート
破壊的に進化する.NET技術のトレンド変化に立ち向かう
― Grani×gloops×Sansan 3社合同 アニバーサリー企画 第5回 勉強会[2]―
数年で根本から大きく変更される.NET技術。そんなトレンド変化に追随するにはどうすればよいのか? gloopsで実践されている手法を具体的に説明する。
.NETの最新技術を紹介する「.NET勉強会」が、8月末にGrani×gloops×Sansan 3社合同で開催されました。本稿では、そのセッション内容を詳しく紹介します。勉強会では、下記の4つのセッションがありました。
- 1ASP.NET Identity とそのセキュリティ
- 2[本稿]ローテクで .NET 技術トレンドの変化に立ち向かう!!
- 3Life with Roslyn ~30分間で分かったツモリになる Compiler as a Service
- 42014年版 C#でできること
本稿では、2の株式会社gloopsの山本昭宏による「ローテクで .NET 技術トレンドの変化に立ち向かう」のセッション内容をご紹介します。本レポートは、話した内容をそのまま書き起こした形式となります。
Sansan主催の「.NET勉強会」について
Sansan株式会社は、スキルアップを目指す.NETエンジニアのための勉強会を定期的に開催しています。本稿は、アニバーサリー企画としてGrani×gloops×Sansanの3社合同で開催された第5回(開催:2014年8月30日、モデレーター:Sansan株式会社 藤倉成太)の内容をレポートしたものです。第5回では、株式会社グラニより田中孝佳氏、株式会社gloopsより山本昭宏氏をゲストに迎え、Sansan株式会社の渋木宏明、熊家賢治とともに、.NETの最新技術や活用状況に関するセッションを行いました。
ローテクで .NET 技術トレンドの変化に立ち向かう ― 株式会社gloops 山本 昭宏
本セッションでは、.NETデベロッパーを対象に、特定の新技術を取り上げるのではなく「既存の技術を組み合わせていかに新技術に備えるか」をテーマに、株式会社gloopsでの取り組みを共有することを目的とします。
.NETテクノロジトレンドの振り返りと課題
――一般的なテクノロジトレンド
一般的なテクノロジのトレンドとして、ユーザーデバイスではモバイルデバイスの利用率の拡大、ホスティングプラットフォームではクラウドの利用率の拡大といったものがあります。
また、ミドルウェア/ライブラリ、特にJavaScript系ライブラリやLinux系ミドルウェアの多様化が進んでおり、非Windowsプラットフォームが拡大している状況と言えます。
――.NETテクノロジトレンド
.NETテクノロジは、2014年4月のMicrosoft Build 2014
(米国サンフランシスコ)で発表された次のようなキーワードのもと、このような一般的なテクノロジの変化に対応しようとしています。
Cloud-First / Mobile-First / ○○vNext
.NET vNextでは、“RyuJIT”、.NETネイティブ(.NET Native)、“Roslyn”といった主にコンパイラーに関する改善が行われています。
ASP.NET vNextでは、MvcController
クラスとApiController
クラスの統合、System.Web
名前空間や、IISに依存しない実装といった大きな変更が行われています。
OSS(Open Source Software)への対応
例えば、Visual StudioのWebアプリケーション・プロジェクト・テンプレートをデフォルトで実行すると、JavaScript系のOSSライブラリがパッケージとして取り込まれます。それ以外にも、Redisのセッションステートプロバイダーが提供されるなど、Visual StudioなどにさまざまなOSSが取り込まれています。
マイクロソフト自身も、Entity Framework、ASP.NET MVC、TypeScript、Roslynなどをオープンソース化しています。
マルチプラットフォーム / マルチデバイス
Xamarin(iOS、Android、Windows、Mac)、Windowsストアアプリ、Windows Phoneアプリなど、複数のプラットフォームやデバイスでコードを共通化しやすくするための仕組みとして、ユニバーサルアプリ(Universal Apps)というキーワードで共有プロジェクト機能を提供しています。
――新しい.NETテクノロジトレンドの課題
まず、近年利用するプラットフォーム、デバイス、ライブラリ、ミドルウェアが多様化していることが大きな課題となっています。
また、.NETテクノロジの破壊的変更の嵐により、技術の取り込みが大変といったことも課題として挙げられます。
OSS対応が進んでいますが、個人ベースのOSSはメンテナンスが突然中断されるというリスクがあります。
さらに、.NETに限ったことではありませんが、新しいライブラリを取り込むと、そのときにはより良いライブラリが出ているといった課題もあります。
テクノロジトレンドの変化に立ち向かうには
破壊的な変更が多いとはいえ、「より良いもの」を目指した変更であるため、新しいテクノロジをいつまでも使わないわけにはいきません。そのため、あらかじめ変更に強い基盤を用意することで、テクノロジトレンドの変化に立ち向かう必要があります。
今回は、開発ライフサイクルにおける、設計/開発/リリースの各ステップに関してその方法を説明します。
――[設計]ソリューション構造/プロジェクト構造の設計
基本方針の決定
最初に、ソリューション構造/プロジェクト構造の基本方針を決定します。ここでは、特定のテクノロジやライブラリへの依存範囲を最小化すること、社外ライブラリを使用する場合はインターフェース経由でアクセスするようにすることを基本方針として設定します。
ソリューション構造のグルーピング
基本方針に基づいて、ソリューション構造のグルーピングを行います。具体的には、依存するテクノロジごとにソリューションフォルダーをグルーピングします。
フォルダー階層の構造は、
<ソリューション名>/<機能名>/<テクノロジ名>
のようにします。
プロジェクト構造の分割
次に、ソリューションフォルダー内のプロジェクト名を整理します。具体的には、ライブラリごとにプロジェクト構造を分割します。
プロジェクト名は、
<ソリューション名>.<機能名>.<テクノロジ名>.<依存ライブラリ名>[.<依存ライブラリ内の階層名など>]
といった順序で設定します*1。
- *1
<……>
は任意の名前、[……]
は省略可能であることを表す。
ソリューションフォルダー階層/プロジェクト名の例
ソリューション構造/プロジェクト構造の決定例を見てみましょう。
これは、gloopsにおける実際のフォルダー階層/プロジェクト名の例です。
ソリューションフォルダーを、「Data」「Lib」「LibExt」などのようにテクノロジ単位で分割しています。
続いて、各フォルダー内で依存するライブラリごとに、プロジェクトを分割しています。例えばソリューション名が「Fango」であった場合、Dataフォルダー内では、データ(Fango.Data)、データベースにアクセスするライブラリ(Fango.Data.Database)、データセットを使用するライブラリ(Fango.Data.DataSet)、Entity Frameworkを使用するライブラリ(Fango.Data.EF)といったようにプロジェクト構造を分割します。
また、外部ライブラリを使う場合には、LibExtフォルダー内でプロジェクトを「AWS」「Azure」「JsonNet」など依存するパッケージ単位で分割します。
ソリューションフォルダーと、その中のプロジェクト群について、次の表にまとめました。
ソリューションフォルダ名 | 格納するプロジェクト |
---|---|
Data | System.Data関連のライブラリ |
Lib | コアライブラリ(実行環境への依存度の低いライブラリ) |
LibExt | 外部ライブラリ |
Web | System.Web関連のライブラリ |
Test | テストプロジェクト |
Exe | コンソールアプリ |
PS | PowerShell関連ライブラリ |
WPF | WPF関連アプリ、ライブラリ |
iOS | iOS関連アプリ、ライブラリ |
Android | Android関連アプリ、ライブラリ |
「Lib」フォルダーには実行環境に依存しないコアライブラリを集め、各ライブラリに対応するインターフェースを用意します。
例)ICacheClient
、ISequenceClient
、IJsonSerializer
、IDataContext
、IDataRepository
など
「Data」フォルダーでは、各Dataライブラリを使用して、コアライブラリで用意したインターフェースを実装します。
例)SqlSequenceClient
、DataSetDataContextAdapter
、EFDataContextAdapter
など
外部ライブラリを使用した実装を行う場合は、「LibExt」フォルダーでインターフェースを使用して各外部ライブラリでコアライブラリで用意したインターフェースを実装します。
例)RedisCacheClient
、JsonNetSerializer
など
非依存ライブラリの明確化
例えば、クラスライブラリのプロジェクトテンプレートを作成すると、デフォルトでSystem.Data
、System.DataSetExtensions
、System.Xml
、System.Xml.Linq
などのアセンブリが参照されます。これらのライブラリはコア機能を実装するクラスライブラリには不要であるため、あらかじめ削除しておきます。
また、不要なライブラリを削除したプロジェクトテンプレートをあらかじめ用意しておくのもよいでしょう。
メリットとデメリット
このようにソリューション構造/プロジェクト構造をテクノロジやライブラリ単位で分割すると、作成したプロジェクトをNuGetパッケージとして扱いやすくなります。また、外部NuGetを含むパッケージの依存性管理が容易になり、外部ライブラリの変化に対応しやすくなります。
一方で、アセンブリ数がとにかく増えてしまうというデメリットがあります。特に外部のNuGetパッケージにはいろいろな依存性があり、細かく分割しきれないこともあるため、その場合はほどほどに分割するようにします。
また、コーディング量が増えてしまうという問題もあります。これはReSharperなどの各種ツールのリファクタリング機能により低減が可能です。
実例
あるクラウドでサービスをリリースし、途中で分散キャッシュをRedis+Sentinelに変更して、最終的にオンプレミスに移行しました。サービスのリリース後、約3カ月でこのようにベーステクノロジを変更できたことから、このようなアーキテクチャはそれなりに効果があると言えます。
――[開発]T4テンプレートによるエンティティモデルとデータリポジトリインターフェイスの生成
データベースアクセス層の悩み
テクノロジ単位で実装する場合、特にデータベースアクセス層の実装が大変です。これは、マイクロソフトが推奨するEntity Frameworkがまだデータアクセス・フレームワークの決定版と言えるほどにはこなれていないことに原因があります。そこで、Entity Frameworkに依存しないように、データアクセス・フレームワークをカスタムで実装しました。
データアクセス・フレームワークの作成
Entity Frameworkの*.edmxファイルに含まれるT4(Text Template Transformation Toolkit)テンプレートをカスタマイズし、そのT4テンプレート内でEnvDte(=Visual Studioのオートメーション自動処理用ライブラリ)を使用して関連ファイルをEntity Frameworkに依存しないプロジェクト内に生成するようにしました。また、カスタマイズしたテンプレートを*.vsixファイルにまとめてNuGetパッケージ化し、社内のNuGetサーバーから取得できるようにしました。
Entity Frameworkに依存したくないのにEntity Frameworkを使っているのは、データベースからモデルなどを自動生成する機能は欲しいが、一から作るのは面倒なので既存のものは使いたいという理由があります。
また、Visual StudioのEntity Frameworkデザイナーを利用できることが大きなメリットになります。
パフォーマンス上の理由から外部キーは使いたくないが、外部キーを使わずにテーブルをモデル化すると、テーブル間のリレーションが分からなくなってしまいます。デザイナーがあれば、論理的なテーブルのリレーションの情報を記述でき、その情報を基にマスター整合性チェックツールを作りやすくなります。
データアクセス・フレームワークの概要
データアクセス・フレームワークでは、基本となるインターフェースとして、リポジトリパターンを表すIDataRepository<TEntity>
インターフェースと、それをまとめるIDataContext
インターフェースを生成します。
これらのインターフェースの役割は、System.Data
名前空間およびEntity Frameworkでは次の役割に対応します。
データアクセス・フレームワーク | System.Data | Entity Framework |
---|---|---|
IDataRepository<TEntity> | DataSet | DbContext |
IDataContext | DataTable | DbSet |
TEntity | DataRow | エンティティ(リレーション)モデル |
さらに、これらの基本インターフェースを拡張するインターフェースから、Entity Framework向けの実装を自動的に生成します(図2)。
データベースアクセス・フレームワークの利用例
例えば、「Canonica」というソリューションがあり、ソリューション内の「Canonica.Data.EF」プロジェクトの「User」フォルダーに、このフレームワークを使ったテンプレートを追加するとします。その手順を説明します。
プロジェクトに対し、[新しい項目の追加]ダイアログで社内NuGetサーバーからインストール済みの項目テンプレートを選択し、自作データアクセス・フレームワークを追加します。すると、Entity Frameworkを拡張した関連ファイルが次の画面のように展開されます。
Entity Frameworkで通常生成されるファイルを拡張し、データコンテキストやデータリポジトリを生成する「ttinclude」ファイル、インターフェースを生成するファイル、モデルを生成するファイルをカスタマイズしています。Entity Frameworkのデザイナーと同じように、データベースからテーブルの定義を取得してモデル化し、これを保存するタイミングで関連ファイルを自動生成します。
Entity Frameworkでは.edmxファイルのプロジェクト配下にモデルやデータコンテキストなどのファイルが生成されますが、このデータアクセス・フレームワークではモデルは別のプロジェクトに生成されます。この、別に生成されたプロジェクトはEntity Frameworkに依存していません。このようにプロジェクトを分けることで、Entity Frameworkを利用できなくなった場合でも、ライブラリを使い回せるようにしています。
実際に生成されるファイルは次の通りです。データソースに依存しないプロジェクトではインターフェースとモデルが生成されます。Entity Frameworkを実装するプロジェクトでは、Entity Frameworkに応じた実装が自動生成されます。
自動生成するモデルにもカスタマイズを加えており、DataMember
属性を付加してシリアライズの対象を明確にしています。また、自動生成されたファイルとカスタマイズされたファイルを部分(Partial)クラスにすることで、簡単にカスタマイズできるようにしています。
――[リリース]簡易Blue-Green Deploymentによるリリース管理の効率化
リリース管理効率の改善
リリースのステップでは、新しいテクノロジやライブラリに限らず、新しいアイデアの実装を安全に、高頻度にリリースしたいという要望があります。
リリース管理効率を改善する手段として、Blue-Green Deploymentがあります。これは、例えば「Blue」という名前の環境と「Green」という名前の環境というような複数の環境を用意し、それらをネットワークで切り替えることにより、新機能のリリース時のゼロダウンタイムを実現するデプロイ方法です。
例えば、一般ユーザーは現在のプロダクション環境であるBlue環境にアクセスしています。新しい機能をデプロイするときには、ステージング環境であるもう1つのGreen環境にデプロイします。デプロイが完了したら、ネットワークのルーターでGreen環境にアクセスさせるようにすることで、ゼロダウンタイムを実現します(図5)。
Blue-Green Deploymentのメリットとデメリット
Blue-Green Deploymentには次のようなメリットがあります。
- デプロイ時間を短縮化できる
- 1つ前の環境にすぐに戻せる
- ステージング環境で事前に動作を確認できる
- ローリングアップデートに対し、デプロイが完了したサーバーと未デプロイのサーバーの混在が発生しない
一方で、理想としては環境ごとにアプリケーションサーバーを分ける方がよいが、複数の環境をホストするためには、その分のリソースが必要になるというデメリットがあります。クラウドではあまり気になりませんが、オンプレミスでは倍のリソースが必要です。
オンプレミスにおけるBlue-Green Deploymentのデメリットを軽減するには
オンプレミスでは、Blue-Green Deploymentのためのリソースコストを減らすために、ハードウェアコストではメモリが一番安いものとして、1つのアプリケーションサーバーにWebサイトを2つホストして、ポートまたはURLでルーティング対象を切り替えることで、少ないリソースで簡易的なBlue-Green Deploymentをする方法を選択しました。
例えば、1つのアプリケーションサーバでBlueとGreenの2つのWebサイトをホストします。一般ユーザーは、ロードバランサー経由で、nginx(エンジンエックス)でさらにロードバランスされた環境にアクセスします。次の図では、現在アクセスしているのは、プロダクション環境であるBlueです。
エンジニアが新しい機能のデプロイを開始すると、デプロイサーバー内のデプロイスクリプトが実行され、監視サーバーのWeb APIを呼び出します。監視サーバーはnginxの構成を変更し、ステージング環境のWebサイト、すなわちGreenをロードバランスの対象から外します(図7)。Greenへのデプロイが完了したら、監視サーバーのWeb APIを呼び出してGreenをロードバランスの対象に復帰させます。
社内のスタッフがステージング環境であるGreenにアクセスし、動作を確認します(図8)。
動作確認の終了後、アクセス先をBlueからGreenにスイッチすることで、ユーザーにとってはダウンタイムが発生しない状況で、新しい機能をリリースできます(図9)。
――おまけ
おまけとしてT4テンプレート開発に関するヒントを紹介します。
T4テンプレートをデバッグ実行しているときに、EnvDteを組み合わせると、次のような例外が発生する場合があります。
- ハンドルされていない例外: System.IO.FileNotFoundException:
- ファイル 'EnvDTE, Version=7.0.3300.0' を読み込み中にエラーが発生しました。
これはバインディングリダイレクトが設定されていないことにより発生します。デバッグ時には、Visual Studioのインストールフォルダー内のCommon7/IDE/T4VSHostProcess.exeが使われることが原因です。そのため、対応するT4VSHostProcess.exe.configファイルを作成してBindingRedirect
の設定を記述し、同一フォルダーに配置する必要があります。
■
最後に、繰り返しになりますが、Sansanでは定期的に.NET勉強会を開催しております。ぜひご参加ください。
※以下では、本稿の前後を合わせて5回分(第1回~第5回)のみ表示しています。
連載の全タイトルを参照するには、[この記事の連載 INDEX]を参照してください。
1. .NET最新技術「ASP.NET Identity」とは?
ASP.NETの資格管理技術がどう進化して、最新のASP.NET Identityが生まれたのか紹介。また、その特徴と機能、構成、処理の流れなどを解説する。
2. 10分間で人に説明できるまで分かるCompiler as a Service“Roslyn”
Visual Studio “14”の新機能として搭載予定の次期コンパイラープラットフォーム“Roslyn”について、簡単に話せるレベルになるまで、ほんの少しだけ踏み込んで解説。
3. C#&.NETの進化と、次期版でできること(2014年版)
さまざまなプラットフォーム向けのプログラムを開発できるまでに進化してきたC#。その内容と特徴を、プラットフォームごとにまとめる。また今後のC#/.NETがどのように進化するかも紹介する。
4. 【現在、表示中】≫ 破壊的に進化する.NET技術のトレンド変化に立ち向かう
数年で根本から大きく変更される.NET技術。そんなトレンド変化に追随するにはどうすればよいのか? gloopsで実践されている手法を具体的に説明する。
5. Xamarinで今日から始めるクロスプラットフォーム開発
クロスプラットフォームアプリ開発の戦略についてまとめ、Xamarinによるアプリ開発の特徴を説明する。また、Xamarinに関する情報収集や、Xamarin.Forms×MVVMによる開発のポイントを紹介する。