Build Insiderオピニオン:岩永信之(8)
見えてきたC# 7: C#の短期リリースサイクル化
C# 7にはどんな新機能が含まれるのかが見えてきた。これまでと比べて、C# 7はかなり速いペースでのリリースとなる。その背景にはどんな事情があるのだろうか。
次期C#として提案されている機能のうち、どこまでをC# 7としてリリースするかが決まってきた。リリース時期は明示していないものの、今このタイミングで機能を決めたということは、今年中のリリースもあり得るだろう。
これまでのC#のリリースサイクルからすると、少し短くなっている。また、新規追加する機能を小さめに区切っている。今回はこのリリースサイクルの短縮についての話をしていこう。
C# 7
C# 7/VB 15(Visual Basic 15)に実装される予定の機能は以下のページにまとまっている。
これで確定というわけではないが、変更は細々としたものにとどまっている。本稿的に重要な点は、このページが作られたのが4月初旬で、並んでいる機能は4月時点で実装のめどがある程度立っていたものということである。
機能としては結構絞られた印象がある。例えば以下のようなものがC# 7から除外された(取りやめではなく、後回しになっただけなのでご安心いただきたい)。
- 型パターン以外のパターンマッチング
- レコード型(次回以降で説明)
- 非null参照型(次回以降で説明)
絞られた代わりといってはなんだが、恐らくリリース時期が近づいている。明確には決まっていないが、C# 6がリリースされたときのペースと比較すると、2016年中のリリースもあり得るだろう。
仮に2016年末のリリースと想定して、これまでのリリース時期と一緒に並べてみよう。図1のようになる。
これまで、C#のリリースは約2年半に1度のペースだった。C# 5.0とC# 6の間は少し長引いたが、これは、コンパイラーを一から再実装する必要があり、この作業に手間取っていたせいであって、例外的である。
一方で、C# 6とC# 7の間はずいぶん短くなっている。これまでの半分程度である。実のところ、C#チームとしては「年に1回程度のリリース」を目指したいようだ。その目標からすると、むしろ遅れ気味なくらいである。
短期リリースの理由
どうしてリリースサイクルが短くなっているかといわれると、「そういう時代だから」と感じる。マイクロソフトは、2000年代には「動きが遅い」などと言われ、何とか改善を図ろうと、ずっと「リリースサイクルを縮める」と言い続けていた。もちろん抱えている製品が大きく、かつ、歴史あるため、これを実現するには困難も大きい。しかし実際、ライバル企業もどんどん製品が大きくなる中、製品のリリースサイクルは短かく保ち続けている。ソフトウェア開発手法や、それを支えるツールも進歩して、生産性は上がっているはずで、リリースサイクルを縮められるはずなのだ。
最近のプログラミング言語は本当にリリースサイクルが短い。例として、Go、Swift、TypeScriptの主要なバージョンのリリース時期を並べてみよう。図2のようになる(参考までにC#も並べている)。
見ての通りの短期リリースである。もちろん、少ない機能を細かくリリースするか、多くの機能を一気にリリースするかの差ではある。リリース頻度が高いものは、小数点以下のバージョンアップで新機能も少ない。中には、パフォーマンス改善とちょっとしたライブラリ追加程度のリリースも含まれている。
しかし、小さいリリースを重ねて、プログラミング言語が少しずつ進化し、ユーザーにも少しずつ慣れてもらうのが今時の流れなのだろう。
ツールの改善
ただし、単に好みの問題で短期リリースサイクルな流れになっているわけではない。リリース作業は、作る側にとっても使う側にとっても負担である。この負担を減らす仕組みが整ってきたことによって、リリースサイクルの短縮傾向が生まれている。
C#チーム側の都合
図1でも触れているが、C#を使ってC#コンパイラーを再実装するために、言語機能の更新が遅れていた時期がある。この時期には他にも、オープンソース化、Gitへの移行など、開発体制の変化もあった。新たな環境への移行には時間がかかったものの、移行が終わった今、開発に勢いが付いている。
C#コンパイラーの実装がC++からC#に変化したのは大きいだろう。C#自体の生産性の高さに加え、C#を誰よりも分かっているC#チームがC#を使って開発できる。リリース作業の負担軽減にはGitも貢献しているだろう。オープンソース化は、開発効率にも影響があったようだ。フィードバックを得やすくなったことから、早い段階で新機能に自信が持て、手戻りを減らしている。マイクロソフトは非常に大きな会社で、社内でのドッグフーディングだけでもかなりのフィードバックにはなっていただろう。しかしやはり、オープンになったことで桁違いのフィードバックが得られている。
C#を使う側の都合
バージョンアップは使う側にも負担となる。最新機能をすぐに試したい人にとっては頻繁なリリースはありがたいだろうが、現状維持を望む人にまで負担をかけてはいけない。
最新のC#を使いたいからといって、開発チーム内の全員に「最新のVisual Studioにアップデートしてくれ」、依存しているライブラリの作者に「最新のC#に書き換えてくれ」、運用担当やアプリのエンドユーザーに「最新の.NET Frameworkを入れてくれ」とは言いにくい(特に、エンドユーザーには全く言えないこともあるだろう)。たとえバージョンアップする意思があっても、すぐには動けないこともある。
バージョンアップに伴う負担を減らすために、以下のような仕組みが必要だろう。
- 既存のものをそのまま使える
・ 古いソースコードをそのままコンパイルできる
・ 古いライブラリをそのまま参照できる
・ 古い環境でそのまま動かせる - 簡単にバージョンアップできる
・ 実行環境をOSに対して管理者権限でインストールするのではなく、アプリ単位にユーザー権限で同梱配布できるようにする
・ 依存するライブラリや開発環境まで含めてバージョン管理システムにコミットできるようにする(もしくはコミットしたものから自動復元できるようにする)
既存のものをそのまま使えることに関しては、C#はもともと恵まれている。以下のように、後方互換性がしっかりしていて、ライブラリ作者やエンドユーザーの環境は据え置きで、自分たちが使うC#のバージョンだけを上げることができる。
- 古いバージョンのC#は、ほぼ最新のC#コンパイラーで動く
- ターゲットフレームワークを設定すれば、最新のC#を使って作ったアプリやライブラリが古い.NET Framework上で動く
バージョンアップの簡単さに関してはC#には足りていなかった部分も多いが、徐々に、表1のような仕組みが整ってきている。
対象 | バージョンアップを簡単にする仕組み |
---|---|
ライブラリ | NuGetパッケージマネージャーを使って、依存しているライブラリの指定したバージョンを、設定ファイル(packages.confまたはproject.json)からビルド時に自動復元できる(NuGetサーバーからの自動ダウンロード) |
実行環境 | .NET Coreでは、アプリの発行形式に同梱(self-contained)モードがあり、これを使うと、実行環境全てをアプリに同梱して、.NET Coreがインストールされていないマシン上で単独実行できるようになる。必要な実行環境バイナリはビルド時に自動復元される |
C#開発環境 | Visual Studioに、VSIX(ユーザー単位でのインストールができる拡張パッケージ)として、C#コンパイラーやプロジェクトテンプレート、C#ソースコードエディターをインストールできる。 ただし現状は、開発者個々人がVSIXをインストールする必要がある。また、プロジェクトごとにVSIXを切り替えることはできない |
ライブラリと実行環境に関してはだいぶ環境が整った。
一方、開発環境の自動復元はまだ不十分だ。開発チーム全員にVSIXもしくはVisual Studio自体の更新を頼む必要がある。また、異なるバージョンのVisual Studioであれば1台のマシンに同時にインストールできるが、拡張パッケージ違いの同バージョンを同時にインストールすることはできない(プロジェクトによってC#コンパイラーのバージョンを使い分けるといったことはできない)。この辺りの問題は、次期バージョンのVisual Studioでの改善を期待したい。
新機能の小出し
リリースサイクルが短くなることで、新機能の提供は小出しになるだろう。ただし、注意点もある。また、小出しになることによる影響についても考えてみたい。
注意点: 機能単位リリースはしない
まず、小出しといっても、機能単位でそれぞれ別リリースにしたりはしない。例えば、タプル型だけが使えるリリース、パターンマッチングだけが使えるリリース、ローカル関数だけが使えるリリースというようなパッケージは作らない予定である。
ただし、あくまでパッケージとしてリリースされないという話で、ソースコード上は機能単位でブランチが作られている。もし機能単位で最新機能を試してみたい場合には、GitHub上のリポジトリから最新のソースコードを取ってきて、所望のブランチに移動してから、自分でビルドして試してみることができる。ビルド結果はVSIX形式のVisual Studio拡張になっていて、ソースコードを取ってきた本人以外に試してもらうこともできる。
ペースの違い
機能ごとに実装にかかる時間に大きな開きがある。例えば、2進数リテラルは案が出てすぐにプロトタイプ実装があったくらい単純だし、ローカル関数もすぐに実装が終わっていた。一方で、タプル型やパターンマッチングの実装はC# 6リリース直後から始まっているもののまだ作業が続いている。また、レコード型や非null参照型はさらに先までかかりそうなので、C# 7から外れそうである。すなわち、機能ごとに実装にかかる時間には、数週程度から数年程度までばらつきがある。
リリースサイクルが長い場合、リリース時期はこのうちで一番長いものにそろいがちである。初期の段階で実装が終わっている2進数リテラルが、安定するまでにまだまだ時間がかかりそうな非null参照型につられて、2~3年先までリリースされないということがあり得る。実際、過去のリリースでは、ジェネリクスや非同期メソッドなどの大きな機能につられて、null許容型やCaller Infoなどの小さな機能も2~3年待たされていた。リリースサイクルの短縮によって、こういうある機能が別の機能の完成を待たなければならない時間は減るだろう。
有用な一部分を優先実装
一般論としてよくある話だが、「2割の実装が8割のユースケースを満たす」というようなことがある(いわゆるパレートの法則)。この場合、その有用な2割を優先的に実装すべきだろう。C# 7では、パターンマッチングを部分的に実装することとなったが、これはまさにその「有用な2割」だ。すなわち、以下のようなことが言える。
- パターンマッチングのうち、実装が単純なのは型パターン
- 型パターンと比べると、再帰パターン(位置指定パターンやプロパティパターン)は利用場面がかなり限られる
そして、型パターンだけがC# 7に取り込まれる。
段階的な普及の意味もあるだろう。「有用な2割」である型パターンになれることによって、「残り8割」である再帰パターンのユースケースも見えてくるかもしれない。正当な進化形なので、「せっかく覚えたのにすぐに書き方が変わるの?」というような心配も必要ない。
もちろん、先に2割をリリースしたことで「残りの8割」に当たる部分の追加実装が阻害されないことだけはしっかり検討する必要がある。提案段階で一度大風呂敷を広げた上で、実際にC# 7に取り込む機能を大きく絞っていることにはちゃんと意味があるのだ。C#利用者としては、「案として出ていた機能が消えた」と悲しむのではなく、「有用な部分だけ早く試せる」と喜ぶべきだろう。
機能間の依存
ある機能が別の機能に依存している場合がある。例えば、ある構文が落ち着いてからあらためて実装を検討したい構文、構文が入ってからでないと効率的に実装できないライブラリや、構文とライブラリを同時にリリースしなければ存在意義が弱くなるものなどがあり得る。C# 7と関連するものでは、以下のようなものがある。
- レコード型は、タプル型やパターンマッチングとの整合性が必要で、これらが落ち着いてからでないと実装が怖い
- ライブラリやアプリのパフォーマンス改善作業の際には、参照戻り値やローカル関数を使いたい
- 標準ライブラリにUtf8Stringクラスを追加する際には、同時にUTF-8文字列リテラルがほしい
- 非null参照型などは、.NETランタイムのレベルで手を入れられるならより良い言語構文にできる可能性がある
依存があるので当然、1世代遅らせないと実装できないということも起こり得る。結果的に、リリースサイクルが長いと、それだけで欲しい新機能や機能改善が遠い未来のことになってしまう。例えばC# 5.0までの2年半サイクルだと、「次の次」は5年も待たされることになる。リリースサイクルの短縮は、こういう依存による遅延の積み重ねを減らす意味がある。
まとめ
C# 7ではリリースサイクルの短縮を目指していて、もしかすると2016年中のリリースもあり得るペースになっている。これまでの2年半に1回程度のリリースからすると、約半分になっている。C#の便利な新機能を一刻も早く使いたい人にとっては朗報だ。
リリースサイクルの短縮は「ご時世」なのだろう。最近のプログラミング言語はいずれもリリースサイクルがかなり短い。開発ツールの生産性も上がり、プログラミング言語を開発する側にとっても使う側にとってもリリース作業に伴う負担が減ったことによって、頻繁なリリースが可能になっている。
岩永 信之(いわなが のぶゆき)
※以下では、本稿の前後を合わせて5回分(第6回~第10回)のみ表示しています。
連載の全タイトルを参照するには、[この記事の連載 INDEX]を参照してください。
6. 次期C#とパフォーマンス向上(前編)―― 必要となった背景と改善内容
機能や構文ばかりが注目されるが、プログラミング言語ではパフォーマンスも重要だ。パフォーマンス向上に対する要求が高まってきた背景と、向上のための改善方法を説明。C# 7以降で追加が検討されている新機能にも言及する。
7. 次期C#とパフォーマンス向上(後編)―― 予定・検討中の5つの新機構
前編に続き、次期C#のパフォーマンス向上について解説。C# 7以降での採用が予定もしくは検討されているパフォーマンス向上関連の新機能の内容を具体的に見ていこう。
8. 【現在、表示中】≫ 見えてきたC# 7: C#の短期リリースサイクル化
C# 7にはどんな新機能が含まれるのかが見えてきた。これまでと比べて、C# 7はかなり速いペースでのリリースとなる。その背景にはどんな事情があるのだろうか。
9. C# 7、そしてその先へ: 非同期処理(前編) - Task-like
C#の進化の中でも「非同期メソッド」はコーディング方法を大きく変えるほど革新的だったが、そこにはまだ課題もある。C# 7~将来のC#で、非同期処理はどう進化するのか、前後編で見ていこう。
10. C# 7、そしてその先へ: 非同期処理(後編)- 非同期シーケンス
C#(とVisual Basic)が切り開いた非同期処理の新たな世界。そこにはまだ課題もある。これを克服する方法として、前後編の後編となる今回は「非同期シーケンス」がC# 7でどうなるかを見てみよう。