2019 年 7 月

Volume 34 Number 7

[C#]

再統合された .NET:.NET 5 に関する Microsoft の計画

Mark Michaelis | 2019 年 7 月

5 月に開催された Microsoft Build 2019 において Microsoft が .NET 5 を発表したとき、デスクトップ、Web、モバイル、クラウド、およびデバイスのプラットフォーム全体を作業対象とする開発者にとっては、重要な一歩を記したことになりました。事実、.NET 5 は、各種のフレームワークを統一し、コードの複雑性を軽減し、クロス プラットフォームの実現を大幅に前進させる希少なプラットフォーム更新です。

これは簡単な作業ではありません。Microsoft では、いくつかの重要なフレームワーク (.NET Framework、.NET Core、および Xamarin/Mono) のソース コード ストリームを統合する計画を打ち出しています。この取り組みによって、今世紀の初頭には別々に分かれていたスレッドを統合して、開発者が作業を行うための 1 つのターゲット フレームワークを提供する予定です。

図 1 のソース コード フローの概念は、各フレームワークのタイムラインがどのように同期され、最終的に 2020 年 11 月に .NET 5 として単一のスレッドに統合されていくかを示しています (画像の中で、.NET Framework は .NET FW と短縮して表記されています)。 .NET 5 がリリースされれば、.NET Framework 4.8、Mono 5.0、および .NET Core 3.0 に代わる地位を占めるでしょう。

.NET、Mono、および Shared Source Initiative から .NET 5 までのソース コード フローの概念
図 1 .NET、Mono、および Shared Source Initiative から .NET 5 までのソース コード フローの概念 (クリックすると拡大します)

実際のところは、ブランチよりもソース コードのフォーク (単なるコピーに近い)、機能 (Windows Presentation Foundation (WPF) や Windows フォームなど) の統合よりも移行を伴っており、図 1 は現実よりも概念的になっています。それでも、この画像は、.NET 5 へとつながる 3 つの主要なブランチからの進化を示し、.NET ソース コードの代々の歴史をかなり明確なビューとして提示しています。

この仕事の成果が、すべてのプラットフォーム (デスクトップ、Web、クラウド、モバイルなど) 上で実行される .NET 5 のフレームワークを利用した統合プラットフォームになります。図 2 は、この統合されたアーキテクチャを示しています。

.NET 5—統合されたプラットフォーム
図 2 .NET 5—統合されたプラットフォーム

誕生ストーリー

各種の .NET のフレームワーク (Microsoft の Shared Source Common Initiative (Rotor)、SilverLight、Windows Phone、.NET Core、および .NET Framework (ただし Mono 以外)) が、元は同一のソース コードからコンパイルされた経緯は、興味深いです。言い換えると、すべてのソース コードが単一のリポジトリ内で保持され、すべての .NET のフレームワークによって共有されていたのです。これにより、Microsoft では、各種のフレームワークに共通する API が同一のソース コードに由来し、同一のシグニチャになっていることを保証できていました。唯一の違いは、どの API が共有されるかでした (.NET "フレームワーク" とカタカナで表記する場合は、一般に .NET のすべてのフレームワークを示し、.NET "Framework" と英語で表記する場合は、.NET Framework 4.8 などの Windows .NET Framework を示します)。

各種のフレームワークをターゲットとする単一のソースを実現するために、#ifdef の多用など、さまざまなサブセット化手法が利用されました。また、Rotor のクロス プラットフォームのサポートを構築するために、交差する一連のサブセット化手法 (つまり、さまざまな #ifdef) が .NET ソース コードにどのように組み込まれ、同一コード ベースからの Silverlight と (さらに後に) .NET Core 両方の迅速な開発を実現できたのかも、興味深いです。

交差する一連のサブセット化手法はそのまま残されている一方で、クロス プラットフォームのコンパイルを実現する手法 (各種のプラットフォームを作成するためのサブセット化) は削除されていっています (例として、古くなった複数の #ifdefs を削除する bit.ly/2WdSzv2 のプル要求をご覧ください)。 今日、それらを削除できるのは、.NET 1.1 のリリース後数日以内に、.NET Core と .NET Framework のソース コードがフォークされた (言わばコピーされた) からです。このことは、実際に .NET Framework (referencesource.microsoft.com) と .NET Core (source.dot.net) に、2 つの別の .NET ソース コード Web サイトが存在する理由を説明しています。これらは、2 つの別個のコード ベースです。

サブセット化の利用を継続せずにフォークするという決定は、下位互換性の維持 (.NET Framework での優先事項) とイノベーション (.NET Core での優先事項) の間での拮抗を反映しています。互換性の維持と .NET API の修正や改善が競合してしまうケースが率直にあまりにも多くなり過ぎて、両方の目標を達成しようとすると、ソース コードを分離しなければならなくなりました。#ifdef の利用は、実際に API が異なっていてバージョン互換性がない場合に、フレームワークを分離させるための機能的な方法ではなくなっていました。

しかし、時が経ち、開発者が両方のフレームワーク内で正常に実行できるライブラリを作成できるようになったことから、別の競合が生じました。これを打開するために、API の標準が必要になりました。標準によって指定された特定の API セットをフレームワークが備えていることを、開発者に保証するためです。このようにして、標準内の API だけを活用すれば、ライブラリは互換可能なクロス フレームワークになりました (厳密に同じアセンブリは異なるフレームワーク上で実行でき、再コンパイルは必要ありません)。

.NET に追加された新しい各機能 (Span<T> など) によって、古いバージョンのフレームワークとの下位互換性を維持することは、ますます難しくなりました。具体的には、(まったく新しい .NET Core のイノベーションとなった) 新しい .NET Standard バージョンでの概念を、.NET Framework においてサポートすることが課題でした。さらに、重要度は高くありませんが、.NET Standard の新しい各バージョンには、NET Framework と .NET Core 間で .NET Standard の互換性を維持するために、保守の負荷になるまで規模が増大していく API セットが含まれていました。

統合する

2 つのフレームワークは、標準ができたことから、さらによく似たものになり始めました。API の一貫性が高くなるにつれて、明確な疑問が生じ始めました。別々になったコード ベースをもう 1 度まとめることはできないのでしょうか。そして、事実として、.NET Core 3.0 プレビュー以降は、.NET Framework WPF と Windows API のほとんどが丁寧に選定されて、.NET Core 3.0 コード ベースに統合されました。これは、実際に起きたことです。.NET Core 3.0 向けのソース コードは 1 つになり、.NET Framework 4.8 での今日の (デスクトップ、クラウド、モバイル、および IoT の) 機能性と同じになりました。

ここまでで、まだ説明していない主要な .NET フレームワークがもう 1 つあります。Mono/Xamarin です。Rotor 向けのソース コードは一般提供されていましたが、それを利用することはライセンス契約に違反しました。Linux と互換可能な .NET バージョンを作成するというビジョンから、これとは別に、まったく新しい別の開発の取り組みとして、Mono が始まりました。Mono フレームワークは、会社 (Ximian) が 2003 年に Novell に買収され、その 8 年後に Novell が Attachmate に売却されて廃業するまで、時間と共に成長を続けました。Ximian の経営は、2011 年 5 月に Xamarin として速やかに刷新されました。そして、それから 2 年経たないうちに、現在はクローズドソースになっている Mono のクロス プラットフォーム バージョンを社内で活用し、Xamarin は Android と iOS の両方で実行されるクロス プラットフォーム UI コード ベースを開発しました。

2016 には、Microsoft が Xamarin を買収し、すべての .NET フレームワークのソース コードを 1 つの会社の傘下に収めました。その後すぐに、Mono と Xamarin SDK がオープン ソースとしてリリースされることになりました。

これで、現在の 2019 年前半まで経緯をたどりました。今後は基本的に、NET Core 3.0 と Mono/Xamarain という 2 つの主要なコード ベースになっていきます (Microsoft では当然ながら .NET Core 3.0 以降に対して Windows 上で .NET Framework 4.8 を サポートします。その一方で、今後の新しいアプリケーション向けの戦略的なプラットフォームとして、.NET 5 がこれに代わる地位を占めるでしょう)。 これと並行して .NET Standard では、間もなくリリースされる .NET Standard 2.1 に API が統合されます。

ここでまた、疑問が生じます。API がより緊密になっていくのなら、.NET Core 3.0 と Mono を統合できないのでしょうか。その取り組みは、実際に既に開始されています。今日の Mono は、既に 3 分の 1 が Mono のソース、3 分の 1 が CoreFx、そして 3 分の 1 が .NET Framework の参照ソースになっています。このことが、.NET 5 が Microsoft Build 2019 で発表されるまでの土台作りになっています。

.NET 5 の利点

統合バージョンであるこの .NET 5 では、すべての種類の .NET アプリケーションがサポートされる予定です。つまり、Xamarin、ASP.NET、IoT、およびデスクトップです。さらに、単一の CoreFX/Base Class Library (BCL)、2 つの別個のランタイムとランタイム コード ベース (意図的に大きく異なる 2 つのランタイムのソースを 1 つにまとめることは非常に難しいため)、単一のツール チェーン (dotnet CLI など) を活用する予定です。その結果、動作、API、開発者のエクスペリエンス全体に統一性が備わります。たとえば、System.* API の 3 つの実装が組み込まれるのではなく、異なる各プラットフォーム上で実行される単一のライブラリ セットができることになります。

.NET の統合には多くの利点があります。フレームワーク、ランタイム、開発者ツールセットを単一のコード ベースに統合することで、開発者 (Microsoft およびコミュニティの双方) による保守や拡張が必要になる重複コードの量が少なくなります。また、最近の Microsoft への期待から、すべての .NET 5 のソース コードはオープン ソースになる予定です。

統合されると、個別の各フレームワークに限定されていた多くの機能が、すべてのプラットフォームで利用可能になります。たとえば、これらのプラットフォームに対する csproj の種類は、よく親しまれているシンプルな .NET Core csproj ファイル形式に統合される予定です。これにより、.NET Framework のプロジェクトの種類では、.NET Core csproj ファイル形式を活用できるようになります。Xamarin および .NET Framework (WPF および Windows フォームを含む) の csproj ファイルでは .NET Core csproj ファイル形式への変換が必要になりますが、その作業は ASP.NET から ASP.NET Core への変換とほぼ同じです。ありがたいことに、ConvertProjectToNETCore3 (bit.ly/2W5Lk3D を参照) のようなツールのおかげで、今日ではさらに簡単になっています。

別の領域として大きな相違点があるのが、Xamarin と .NET Core/.NET Framework のランタイムです。前者は、ソース コードをプラットフォームのネイティブなソース コードに戻してコンパイルする Ahead-of-Time (AOT) コンパイルによる、静的コンパイル モデルを利用します。これに対し、.NET Core と .NET Framework では、ジャストイン タイム (JIT) コンパイルを利用します。さいわい、.NET 5 では、対象となるプロジェクトの種類に応じて、両方のモデルがサポートされています。

たとえば、ランタイムに JIT コンパイラ (jitter) を使用する単一の実行可能ファイルか、iOS または Android プラットフォーム上で動作するようにネイティブ コンパイラを使用する単一の実行可能ファイルに、.NET 5 プロジェクトをコンパイルすることを選択できます。ほとんどのプロジェクトでは、jitter を活用しますが、iOS の場合、すべてのコードが AOT です。クライアント側の Blazor の場合、ランタイムは WebAssembly (WASM) であり、Microsoft では少量のマネージド コード (約 100 KB から 300 KB) を AOT コンパイルすることを予定し、残りにはインタープリター方式が適用されます (AOT コードは大規模なので、通信コストの支払いは大きな負荷となります)。

.NET Core 3.0 では、1 つの実行可能ファイルにコンパイルできますが、その実行可能ファイルは実際には、ランタイムでの実行に必要なすべてのファイルの圧縮バージョンです。ファイルを実行すると、まずはそれ自体が一時ディレクトリに展開され、すべてのファイルが格納されているディレクトリからアプリケーションのエントリ ポイントが実行されます。これに対し、.NET 5 では、その場で直接実行できる本当に単一の実行可能ファイルが作成されます。

.NET 5 のもう 1 つの優れた特性は、Java および Objective-C (Swift など) からのソース コードとの相互運用性です。これは、初期リリース以来の Xamarin の特性でしたが、すべての .NET 5 プロジェクトに拡張される予定です。たとえば、お使いの csproj ファイルに jar ファイルを組み入れることができ、.NET コードから Java または Objective-C コードへの直接呼び出しが可能になります (残念ながら、Objective-C のサポートは Java よりも後になる見込みです)。 .NET 5 と Java/Objective-C 間の相互運用性がインプロセス通信のみをターゲットとしていることには、留意する必要があります。同じコンピューター上にある他のプロセスや、別のコンピューター上のプロセスにも分散された通信では、多くの場合、REST または RPC ベースの分散型呼び出しへのシリアル化が求められます。

.NET 5 に含まれない機能

.NET 5 のフレームワークでは主要な API セットが利用できますが、この 20 年ほどの間に開発されたあらゆる機能が含まれているわけではありません。.NET Standard 2.1 で指定されているすべての API がサポートされることを期待するのはもっともですが、Web Forms、Windows Communication Foundation (WCF) サーバー、Windows Workflow を含め、もっと "レガシ" な API のいくつかはサポートされません。これらは、.NET Framework のみに留まることになります。.NET 5 内で同じ機能性を実現したい場合は、これらの API を次のように移植することを検討してください。

  • ASP.NET Web Forms => ASP.NET Blazor
  • WCF サーバーおよびリモート => gRPC
  • Windows Workflow (WF) => Core WF (github.com/UiPath/corewf)

WCF サーバーのサポートが行われないことは、一部の人にとって間違いなく残念なことです。しかし、Microsoft では最近、MIT オープン ソース ライセンス下でソフトウェアをリリースすることを決定しました。このソフトウェアはコミュニティの管理下に入ることになります (github.com/CoreWCF/CoreWCF を参照)。.NET Framework を独立してリリースするにはまだ行うべき作業がたくさんありますが、その間にも、クライアント側の WCF API は利用可能です (github.com/dotnet/wcf を参照)。

目的の宣言

Microsoft では、.NET 5 の下に自社の開発者フレームワークを統一する計画を立てると共に、統合された .NET リリースに向けては一定の歩調で進めていくことを発表しました (図 3 を参照).今後は、各年の第 4 四半期に .NET の一般提供バージョンがリリースされる見込みです。これらのリリースのうち、2 回に 1 回のバージョンが Long Term Support (LTS) リリースとなり、最低 3 年間または次の LTS リリース後 1 年間のうち、いずれかのより長い期間、Microsoft によるサポートが行われます。つまり、次の LTS リリースにアプリケーションをアップグレードするまで、常に最低 3 年間の猶予があることになります。.NET Core のサポート ポリシーについて、また、.NET 5 になってからサポート ポリシーを上回ることが十分に期待できる機能性について詳しくは、bit.ly/2Kfkkw0 をご覧ください。

.NET のリリース スケジュール
図 3 .NET のリリース スケジュール

現時点で、.NET 5 はまだ発表されたばかりです。目的の宣言、と言ってもかまいません。取り組むべき作業はたくさんあります。それでも、この発表は注目に値します。.NET Core が最初にリリースされたとき、その目標は、Azure (恐らくは特に、Azure の Platform-as-a-Service (PaaS) の部分と、Linux 上および Linux コンテナー内での .NET のサポート) を活かせるクロス プラットフォームの .NET バージョンを提供することでした。

元の概念では、すべての .NET Framework を .NET Core に移植できるという考え方は、現実的とは見なされませんでした。.NET Core 2.0 のリリース前後から、その見方が変わり始めました。Microsoft では、1 つのフレーム上で実行されるコードをほかへ移植できるようにするには、すべての .NET フレームワークのバージョンに対応するフレームワークの標準を定義する必要があることに気付きました。

この標準は、もちろん、.NET Standard と呼ばれるようになりました。その目的は、標準をターゲットとするライブラリが、利用可能な特定の API セットに依存できるように、フレームワークによってサポートする必要がある API を特定することでした。結果的に、標準を定義して Xamarin/Mono、.NET Core、.NET Framework に実装することは、.NET 5 の統合戦略を実現するための重要な要素となりました。

たとえば、.NET Standard の API セットをサポートするコードを各フレームワークに実装した場合、別個のコード ベースを 1 つにまとめることを目指して取り組むことが、理に適っているように思えます (並べ替えのリファクタリング)。また、動作が同じでない場合 (たとえば、JIT と AOT のコンパイルなど)、すべてのプラットフォーム上で両方の手法および機能をサポートできるようにコードを統合するとよいでしょう。小さな取り組みですが、結果として、複雑さの軽減や保守作業の削減、また同時に、すべてのプラットフォームへの機能の統合において、大きな一歩になります。

驚かれるかもしれませんが、統合を実現した .NET Standard そのものによって、.NET Standard との関連が断たれる見込みです。事実、.NET 5 の出現によって、新たな .NET Standard バージョンが登場するかは疑問です。.NET 5 とその後の各バージョンが標準になりそうです。

まとめ

タイミングがすべてという言葉がありますが、.NET 5 には、まさにこれが当てはまります。.NET Framework の事実上の総合的な書き直しは、.NET Core の開発が始まった頃には考えられませんでした。当時、Microsoft では Linux 上、コンテナー内、および PaaS 上で Azure ホスティングのエクスペリエンスを大幅に拡張するという需要に対応していました。このように、当社では、顧客や Azure 製品チームの需要を満たすための取り組みに注力しました。

.NET Core 2.0 では、.NET Framework 内の機能性と一致させることにまで、その使命が拡大されました。ここでも、チームは、過度に機能を引き継ぐのではなく、価値あるものをリリースすることに注力しました。しかし、.NET Core 3.0 と .NET Standard 2.1 の実装から、状況が変わり始めました。新しい機能の登場やバグの発生時に 3 つの個々のフレームワークに対して変更を加えなければならないという考え方では、作業が反復的になり費用がかかります。そして、優れた開発者なら誰もがそうするように、単一のコード ベースにできる限りコードをリファクタリングするという考え方がすぐに採用されました。

こうして、.NET 5 が誕生しました。その誕生と共に、各フレームワークのすべての機能を統合するという考え方が生まれました。それが、シンプルな csproj形式であり、オープン ソース開発モデルの採用であり、Java および Objective-C (Swift を含む) による相互運用性の実現であり、JIT および AOT コンパイルのサポートです。このように、統合された単一のフレームワークという考え方は、明確な次の一歩になりました。Microsoft 内外のすべての人からこのことが歓迎されるように願っています。


Mark Michaelis は、IntelliTect の創設者で、同社でチーフ テクニカル アーキテクト兼トレーナーを務めています。彼は約 20 年間 Microsoft MVP に認定され、2007 年から Microsoft Regional Director を務めています。Michaelis は、C#、Microsoft Azure、SharePoint、Visual Studio ALM など、マイクロソフト ソフトウェアの設計レビュー チームにも所属しています。開発者を対象としたカンファレンスで講演を行い、多数の書籍を執筆しました。最近では、『Essential C# 7.0 (6th Edition)』を執筆しています (itl.tc/EssentialCSharp)。連絡先は、Facebook (facebook.com/Mark.Michaelis、英語)、ブログ (IntelliTect.com/Mark、英語)、Twitter (@markmichaelis、英語)、または電子メール mark@IntelliTect.com (英語のみ) です。

この記事のレビューに協力してくれたマイクロソフト技術スタッフの Rich Lander 氏に心より感謝いたします。


この記事について MSDN マガジン フォーラムで議論する