BT

最新技術を追い求めるデベロッパのための情報コミュニティ

寄稿

Topics

地域を選ぶ

InfoQ ホームページ アーティクル クラウドネイティブコンピューティングのための新プログラム言語 Ecstasy

クラウドネイティブコンピューティングのための新プログラム言語 Ecstasy

原文(投稿日:2019/11/08)へのリンク

Ecstasyは、Tangosolの創業者であったCameron Purdy氏とGene Gleyzer氏によって開発された言語です。先頃のCloudNative London 2019で発表されました。プロジェクトのスポンサであるxqiz.itを創業する前のPurdy氏は、Oracleのシニアバイス・プレジデントとして、エンタープライズJavaやWebLogic、Coherence、Traffic Director、HTTP、JDBC、Exalogic関連製品に関わっていました。同言語とそれが解決を目指した問題について、氏にインタビューしました。

InfoQ: Ecstasy言語(XTC)とは何でしょうか?

Cameron Purdy: Ecstasyは汎用目的でタイプセーフなモジュラープログラミング言語です。クラウドのために開発されました。私たちが過去30年間で学んできたことを活かして、改良し、使いやすい言語を作り上げました。

ある意味において、Tangosol Coherenceの開発に使えたならば、と思うような言語になっています。Webやバックエンドサービスの開発にこれが使えれば、というものを形にした言語なのです。Oracle Cloudインフラストラクチャのパーツ開発に着手した時に、こういうことができれば、と思っていたような言語でもあります。

セキュリティや構成や可読性を重視する一方で、リポジトリや継続的インテグレーション(CI)、DevOps、継続的デプロイメント(CD)、クラウドとクライアントの可搬性、エッジ/CDN/5G統合、地理的分散システムといったものを明確に意図して設計されています。

ただの新言語ではありません。Ecstasy言語は、新たなインストラクションセットを持ち、ジャストインタイム(JIT)やアヘッドオブタイム(AOT)、適応的コンパイル(adaptive compilation)をサポートするために設計された新たなマネージドランタイムをベースとする、新しいバイナリフォーマットにコンパイルされます。

InfoQ: 挙げられた内容からは(私の理解が正しければ)、システムプログラミングを意図した言語ではない、というように思われますが?

Purdy: システムプログラミング言語ではありません。つまり、オペレーティングシステムやドライバ、あるいはメモリの管理を行ったり、ワードプロセッサのようなものを記述するために設計された言語ではない、ということです。もちろん、汎用言語ですから、そういった目的に用いることも理屈の上では不可能ではありません。ですが、プログラミング言語には目的といものがあります。この言語は、クラウド用アプリケーションの構成と改善を支援することを目的として作られたものなのです。

この種のアプリケーションは多くの部分から成り立っていて、それぞれがクラウドプロバイダのデータセンタやCDN、通信会社の5Gインフラストラクチャ、各ISPの提供するエッジ、ダウンロードされたクライアントデバイス、さらにはそのクライアント上で動作するブラウザ内など、さまざまな場所で動作しています。

私たちの目標は、JavaやC#(いずれも私自身が以前からプログラムしていた言語です)、Swiftなどを知っていれば、事前に学習しなくてもEcstasyのコードを読むことができて、数時間ないし数日あればコードを書くことができるようになることです。言語機能の大部分はCやC++開発者ならばよく知っているもので、技術的にはCファミリーに属する言語ですが、そういった人たちが中心的なターゲットではありません。KotlinやPython、Erlang、Elixir、Smalltalk、Rubyなどのユーザにも、Ecstasyはすぐに理解できると思います。Ecstasyの持つ言語的なアイデアや機能は、これらの言語がすでに備えているか、あるいは導入過程にあるものだからです。

JavaやC#と同じように、Ecstasyもマネージドランタイム環境用にデザインされていますが、後発の強みを活かして、マネージドランタイム環境のコンセプトをより活用できるような設計になっています。代表的な例がスレッド処理です — Ecstasyでは、スレッドの概念を表面には出していません。ランタイムが並列性を動的に管理する上で障害となるからです。(プログラム言語でスレッドの概念を表に出さないことには、他にも多くのメリットがあります。開発者が正しい並列コードを書こうとして落とし穴に陥ることを防ぐのも、そのひとつです。) Ecstasyでは、潜在的な並列性や非同期性を持った処理へのスレッドの割り当てはランタイムによって行われます。私たちは並列性とスレッドの問題に対して、Javaの"Hotspot"対応コンパイラの概念を適用しました。これによってランタイムは、コードの実行中に収集した経験的証拠を使用して、同じコードを次回に実行する時に最適化することが可能になります。さら設計面ではアヘッドオブタイム(AOT)コンパイルも考慮されていて、コンパイルや最適化に関わる重い処理をコード実行前に行っておくことが可能です。さらに適応的コンパイルによって、時間の経過に従って情報の収集と最適化の改善を行い、以降の使用に — アプリケーションが停止した後であっても — 活用することができます。

さらに私たちは、JVMやCLRが開発された1990年代以降の、ハードウェアの劇的な変化についても理解しています。当時10万ドル台のハイエンドサーバは、2~4の並列ハードウェアスレッドを備えて、数GBのRAMを持つものが一般的でした — 現在では携帯電話でも、その程度のスペックを備えています。私たちがEcstasyの設計に着手するにあたって、プロセス毎に数十TBのRAMを備え、プロセス毎に数千のハードウェアスレッドを実行するようなサーバでの動作を念頭に置きました。その結果として、"スレッド"や"同期"といった概念を言語から取り除き、不変性(immutability)のような概念を加えることになりました。"ヒープ"のような基本的な概念についても、極めて意図的に排除しています。また、アクタモデルを(SmalltalkのメッセージやErlangのプロセスのように)組み込みで採用することにより、アーキテクトや開発者がアプリケーションを、潜在的に並列性を持ったユニットに簡単に分割できるようにしました。このユニットを、Ecstasyではサービスと呼んでいます。メモリやスレッディング、セキュリティに関するルールはすべてサービスの観点で説明されるため、結果として非常に明確なものになりました。

もうひとつ、言語の美しさを明確にしているものが、型システムです。Ecstasyは静的に型付けされた言語で、優れた型推論とジェネリックな具象化を備えています。それだけではありません。型システムの設計とランタイムの設計に一貫性があるのです。別の言い方をすれば、これら2つが同時にモデル化されたものであるため、型システムがランタイム定義に対して合理的であるとともに、ランタイムも型システムの観点から合理的な設計が行われています。プロパティや変数、オブジェクト参照などもオブジェクトであるため、ランタイムのリフレクションが自然なものになり、ランタイムと型システムが共生的に動作します。このような設計判断は、型システムにおいて証明可能な(provable)クロージャの設計、階層的(ネスト可能)なランタイムコンテナのサポート、セキュアでダイナミックなコードローディングの設計などにおいて、非常に重要な意味がありました。

InfoQ: crate/npm/depのようなものは計画していますか(するべきではないという教訓もたくさんありますが)?

Purdy: この分野は、言語とランタイムの設計にあたって意図的に重視した部分です。私たちの考え方の一部は、多種多様な環境において、さまざまなライブラリやフレームワークやサービスと共に使用されるような、ライブラリやフレームワーク、アプリケーションを開発した経験に基づいています。

例えば、ずっと以前に私が働いていたある企業では、XML解析にSAXやDOMのライブラリを使用していました。ある日、まったく互換性のないAPIの変更が行われたため、古いバージョンと新しいバージョンの両方に対応するコード記述と構築を行って、どちらが選択されても対応できるようにする必要が発生しました。さらに不都合なことに、このライブラリは多くのアプリケーションサーバで使用されていたため、古いバージョンのアプリサーバでは古いバージョンのライブラリを使用し、新しいバージョンではライブラリの新しいバージョンを使用するような状況になったのです。当時の私たちは、さまざまなバージョンのさまざまなアプリサーバを使用するユーザを抱えていたため、そのApache XMLパーザを依存関係として持つ製品を提供することができなくなっていましました! そのために私たちは -- これは冗談ではありません -- 独自のXMLパーザを(依存性を回避するために)用意して、それをずっとサポートせざるを得なくなったのです!

もうひとつの例として、私たちは、Springと当社の製品が正しく動作するようにしたいと思っていました。そのためにSpring開発者たちと共同で作業したのですが、Spring(私たちのユーザの多くは使用していませんでした)への過度な依存を避けると同時に、Springが私たちの製品に過度に依存しないようにするため、すべての統合をリフレクション経由で行わなくてはなりませんでした! その結果、通常ならば1行のコードで書けるようなものが20行のコードになった上に、そのような複雑な処理があちこちに散らばることになったのです。HibernateのプラグインやSolarmetric KODOも同じように追加したのですが、今度はこのような"オプション"ライブラリのさまざまな組み合わせが問題になりましたリフレクションを使えばJavaのModularityの利用が可能になりますが、これは大変な作業です。OSGiを導入して簡略化できないか試してみましたが、結果はさらに複雑になってしまいました。

アプリケーションを開発する企業と共同で作業する時には、多くの場合において、これらと同じ問題が発生していました。これらすべての経験から学んだことを取り入れて、Ecstasyをゼロから設計して、このような問題を解決したのです。まず最初に、コンパイル単位がモジュール、あるいはモジュールのセットになるように設計を行いました。モジュール間に循環参照が存在する場合などには、これが必要になります。次に、モジュール(のみ)のユニバーサルなIDをURI(Uniform Resource Identifier)形式で宣言できるようにして、リポジトリのサポートを組み込みました。モジュールが依存関係を持つ場合には、その依存関係はURIとして表現されます。この関係を、依存モジュールがインポートされる、と呼んでいます。

少し話題から外れますが、モジュールのインポートの簡単さとその動作のエレガントさはとてもクールです。インポートされたモジュールは、インポートしたモジュール内のパッケージ(つまり名前空間)として表現されます。インポートされたモジュールの内容がすべてパッケージにコピーされたような状態なので、パッケージ内ではすべてローカル名でアクセスできるようになるのです。例えば、すべてのモジュールは"Ecstasy.xtclang.org"(URI)を"Ecstasy"パッケージとしてインポートするので、Ecstasyモジュールの"collections.HashMap"クラスには、どのモジュールにおいても"Ecstasy.collections.HashMap"クラスとして表現することができます。

開発されたモジュールにはバージョンがスタンプされます — 一般的には開発バージョンか、あるいはCIバージョンが使用されます。バージョンにはSemantic Versioning 2.0.0仕様をサポートしたバージョン番号も含まれます。バージョンのスタンプは変更可能なので、テストにおいてレグレッションのなかったCIビルドにはQCあるいはプレリリースビルドと記録しておくことができます。ロールアウトの準備が整ったら、プレリリースのマークを取り除けばいいのです。これらはすべて自動化を念頭に設計されていて、組織の既存プロセスに適応するための柔軟性を備えています。

Ecstasyのモジュール設計が独創的な部分がもうひとつあります — ひとつのモジュールに、同じモジュールの異なるバージョンを含むことができるのです。違うバージョンのモジュールを組み入れても、モジュールのサイズはその差異分が増加するだけです。これによって、ひとつのモジュールファイルにひとつのサポートバージョンだけでなく、次期バージョンのプレリリース版や、旧バージョン用の公式パッチなどを含むこともできます。この背景にあるのは、ロールフォワードとロールバック、A/Bテスト、オプションパッチの安全な配布、すべての提供物をひとつのパッケージにする、といった考え方です。

そして、モジュール依存性はハードな依存性である必要はありません。例えば、モジュールAを"required"、モジュールBを"desired"(参照可能であればリンクする)、モジュールCを"supported"(依存グラフ内の他のモジュールがそのモジュールをリンクする場合にのみリンクする)というように参照することが可能です。モジュールを組み込む(embedded)、つまり、物理的に取り入れることもできます。これは主として(組織的な理由などから)複数のモジュールで構成されたものを、単一のモジュールとして提供したい場合を意図したものです。

しかしながら、最も有効な使い方は、これらの機能の組み合わせにあります。モジュールは実行時に存在する場合もあれば、そうでない場合もあります。存在したとしても、必要なバージョンである場合とそうでない場合もありますし、特定のクラスや機能を含んでいない場合もあります。これがいわゆるDLL地獄の実態です。Ecstasyでは、クラスとコードの存在を、バージョンや他のクラスの存在に対して条件付き(conditional)とする機能を提供しています。コンパイラはこのような条件を、複数のバージョンをひとつのモジュールに配置する場合とほぼ同じような方法でコンパイルして、最終的なモジュールに格納します。つまり、そのモジュールは、他のモジュールが存在する場合としない場合、あるいはバージョンの異なる場合をサポートすることが可能なように、動的リンクプロセスの一環として生成されるのです。これにより、モジュールに対するハードな依存性や、特定のバージョンのモジュールに対する依存性を回避することができると同時に、モジュールが存在した場合には、そのモジュールないしバージョンを統合してフル活用することが可能になります。

これらの情報はすべてモジュールにエンコードされているので、すべての条件のテストを自動で行うことができます。テストに関して言えば、ユニットテストや機能テスト、統合テストをモジュールに統合することも可能です。さらに、特定のバージョンが必要でない場合と同じように、実運用で使用するモジュールにはテストは含まれません。

私たちが重視して、その設計に多大な労力を注いだものがこれであることは、現在では間違いありません。では、それはなぜなのか? さまざまな理由の中から特にあげられるのは、CVEやゼロディ、非互換的な変更が製品に持ち込まれるからです。"どのバージョンがどのバージョンでテスト済か"、というマトリックスが、必要な時に用意されている状況を想像してみてください。あるバージョンで退行テストや受入テストを行う場合に、そのバージョンのモジュールが事前に組み込み済であれば、便利だと思いませんか? A/Bデプロイメントで新しいパッチの展開が可能で、さらに、その結果を前バージョンと比較できるようにパッチが分離されていて、実際にどのような変更が行われるかをエンドユーザが事前に -- しかもライブで! -- 判断できるようになれば、と思わないでしょうか。

これらの機能をサポートする設計は可能ですが、ツーリングや自動化(基盤部分の機能に依存します)の部分が整っていないので、まだ実現はしていません。

InfoQ: DevOpsの意図する範囲は、プログレッシブデリバリ(progressive delivery)にまで及ぶものなのでしょうか?

Purdy: そのとおりですが、簡単に実現するものではありません。最初に受け入れておかなければならないことのひとつは、アプリケーションにはバージョンスキュー(version skew)が付き物であり、プログレッシブデリバリはバージョンスキューの一例に過ぎない、という事実です。古いバージョンのアプリケーションクライアントと新しいサーババックエンド、あるいはバックエンドのサービスインスタンス間というように、アプリケーションの異なるバージョンを実行すれば、バージョンスキューはいつでも発生します。いずれの場合においても、プロトコルの相互運用性や状態の互換性が必要になります。この要件は、それ自体が重要なものです。状態に関しては、旧バージョンのコードが、新しいバージョンのデータでも破綻なく動作する必要がありますし、新バージョンのコードは、古いバージョンのデータを受け入れられる(さらに自動的にアップグレードできる)必要があります。

私たちは、バージョンスキューは例外ではなく、現実的なアプリケーションにおいては必然的に発生する一般的な状況なのだ、という事実をまず受け入れることにしました。私たちは以前、POF(Portable Object Format)の設計を行った時、スキーマの前方互換性と後方互換性を実現する作業の中で、この問題を実際に経験していました。その中で、バージョンスキューを受け入れて安全性を確保することは、プログレッシブデリバリや増分型ロールアウト、従来型のA/B(およびその自動化)などにおいても、前提となるものであることを理解したのです。スケールアウト環境において、サービスの中断を回避するためには、アプリケーションの新バージョンの立ち上げと並行して、旧バージョンのアプリケーションの運用を一定期間続ける必要があります。(新バージョンのロールアウトで何らかの問題が発生すると、事態はさらに複雑になります。アプリケーションを以前のバージョンにロールバックしなければならないため、新しいバージョンは、古いアプリケーションの動作継続を妨げることのないように、アプリケーションの状態を変更してはなりません) そのため、私たちの設計作業では、オブジェクトのシリアライズやデータベースのインターフェース設計がこの要件を満たすように、当初から考慮していました。

強力なモジュールバージョニング機能とリソースインジェクション(アプリケーションが外部とコミュニケーションする唯一の手段)を取り込むことによって、新バージョン(すべてのテストモード機能を有効にしたもの)と旧バージョンを実行すると同時に、新バージョンによる状態変更を不可視にして、クライアントに対する応答を実際には配信しないような"箱の中"に留めることのできるような、自律的インフラストラクチャが実現できました。これにより、運用データベースにダメージを与えたり、エンドユーザに影響を与えるようなリスクを回避しながら、実運用のワークロードで新バージョンをテストすることが可能になります。同じように、自律的なインフラストラクチャであれば、インクリメンタルに始めて、新バージョンを実行するサーバをウォーミングアップし、旧バージョンから新バージョンへ段階的にトラフィックを移行するという、同じような方法でアップグレードをロールアウトすることが可能になります。問題が発生した場合には、元に戻すこともできます。実際のワークロードを旧バージョンから新バージョンに移行する前に、アプリケーションの新バージョンを一定期間、明確なレグレッションが存在しないことを実証できるまで運用することが可能であれば、それが理想的です。同じように、最初は旧バージョンのトラフィックの一部を移行して、その後で大部分を移行していくような方法を採用すれば、アプリケーションを利用するエンドユーザが問題に直面した場合にも、影響を限定的にすることが可能になります。

データベースAPIに関しても、最終的にステートフルなシステムを階層的構成のインフラストラクチャ全体で運用するような意図を持って設計されています。アプリケーションの一部をCDN(Content Delivery Network)とエッジティアで運用して、最終的に5Gタワーに移行することが最終的な目標です。これを実現するためEcstasyは、セキュアに組み込み可能な言語として設計されています。データベースAPIではアクタベースのモデルを採用して、動作ユニットと最終一貫性について考慮した設計が行われています。最終的には、同じAPIのサポートをクライアントレベルにまで広げることが目標です。そうすることで、ネットワーク接続が断続的な場合やオフラインでも、アプリケーションが機能するようになるからです。これらはまだ構想段階ですが、APIの初期バージョンが固まった時点で、どのようにサポートできるのかを示す概念実証を提供したいと思っています。

InfoQ: WASMに注目が集まっている中で、XTCを選んだ理由は何ですか?

Purdy: まず明言しておきたいのは、現時点ではサポートしていませんが、x86/x64とARMに加えて、WASMも設計目標のひとつだということです。Ecstasyの目標のひとつは、ユーザの目の前にあるものから、バックエンドシステムの奥の奥まで、すべての共有コンポーネントをサポートすることにありました。これはつまり、ブラウザ内部に至るまでプログラムモデルがポータブルである、ということです。クライアントの普及において、ブラウザは重要な部分を占めているからです(クライアントのiOSやAndroid、macOS、Windows上でネイティブに動作することに加えて、です)。

ブラウザをターゲットにする場合は、JavaScriptへの変換と、WASMへのコンパイルが可能です。私自身は生成されたJavaSciptをデバッグするのはまっぴらなので、どちらを選ぶかは明らかです。さらに忘れてならないのは、LLVMがすでにWASMをサポートしている点です。WASMはLLVMプロジェクトの重要な部分を占めていますし、私たちはコンパイラバックエンドとしていつもLLVMを想定しているのです。

InfoQ: 誰が、どのように使用するのでしょうか?

Purdy: 私たち自身がすでに製品開発に使用しています。Esctasyを一度使用すると、もう他の言語に戻ることは困難だ、ということをすでに体験しています。病みつきになる言語です。その一方で、現在も活発な開発が行われているので、まだ中核的言語というレベルには達していません。例えば、現実的なアプリケーション開発にはまだ不十分です。言語やコンパイラ、ツールチェーンに特に関心がないのであれば、Ecstasyの採用は時期尚早でしょう。

2年経ってプロダクションユースに耐えられるようになれば、誰が使うのか分かります。クラウド用のアプリケーション、さまざまなクライアントで動作する必要のあるアプリケーション、ステートフルなサーバレスバックグラウンド開発などで使用されることになるでしょう。自動化やサービス性、管理性、ソフトウェアライフサイクルの大幅な削減を可能にする言語設計、といったものに恩恵を受ける開発者が採用することになると思います。

私が過去25年間に勤務した企業の大部分では、IT予算の95パーセント(通常はもっと!)を、古いシステムの運用に費やしていました。そのような状況では新たな開発はもちろん、既存アプリケーションの大幅な改善であっても、困難か、あるいは不可能です。長い時間を掛けてそのコストモデルをひっくり返すための、これが最初のチャンスです。Ecstasyは、発想の世代交代なのです。

Ecstasyはオープンソースです。ランタイムも、ツールチェーンも、クラスライブラリも、すべてです。完全にオープンなのです。ライセンスには、標準的なApacheオープンソースライセンスを使用しました。フォークすることも自由ですし、組み込みも可能です。EcstasyのトレードマークはEcstasyプロジェクト(言語をメンテナンスする組織)が所有しますが、ブランド以外、企業や開発者が望むことはすべて自由に行うことができます。

InfoQ: サーバレスとKubernetesの板挟みになるようなことはありませんか?

Purdy: Ecstasyはサーバレス用に設計された初の言語です。マーケティング的なナンセンスにも聞こえますが、そうではありません。これ以前の言語は(JavaScriptなどわずかの例外を除けば)、ネイティブなクラスライブラリと実装、オペレーティング・システム(あるいはOSの公開する領域)、物理的マシンによる階層構造の上に構築されていました。問題は、各層が下位層を隠蔽していないことです -- そして、それには理由があるのです!

Amazonの現在のサーバレスを見てください。実際には専用のサーバを提供しています。(裏側に隠れてはいますが、実際にはそうです) なぜでしょう? サーバレスワークロードが実行する対象をその環境とOSと"マシン"(もちろん仮想です)にすることで、複数のアカウントがマシンを共有することによるリスクを回避しているのです。

Ecstasyはマシンを表に見せません。OSや、OS上で検索したライブラリもそうです。代わりにEcstasyでは、IOC(Inversion of Control)を使用します。アプリケーションが起動後、リソースを見つけるためにコンピュータの中を探し回るのではなく、Ecstasyがアプリケーションにリソースをインジェクトするのです。データベースが必要? こちらをお使いください。ファイルシステム? こちらをお使いください。ブロック・ストレージ? こちらをお使いください。HTTPアクセスが必要? こちらをお使いください。Webサービス? こちらをお使いください。アプリケーションコードの実行環境をすべて隠蔽するように明示的に設計された言語は、これが初めてです。アプリケーションがホストされる(Ecstasy)コンテナのさまざまなリソースのすべてを、言語が完全に管理することのできるというのも初めてのことです。Ecstasyはセキュリティ層を重ねた後付けのものではなく、セキュアに設計された言語です。

さらにEcstasyは、設計レベルからサーバレスです。Kubernetesについて言うならば、当初は存在しなかったような恐ろしく複雑な問題に対処する、素晴らしいエンジニアリングソリューションだと思います。すでに多くのプロジェクトで採用されていますから、Kubernetesは非常にうまくいくと思っています。それらの複雑なシステムの運用を続ける上で、Kubernetesは最も抵抗の少ない手段なのです。

ですが今は、変化の時です。現在のアプリケーション開発は、極めて複雑なものになっています。数十の、時には数百にも及ぶライブラリやコンポーネントを取りまとめなくてはなりません。Nodeや、他の言語の同等なものを見ても、セキュリティの確保やメンテナンスはほぼ不可能に近いものになっています。

Ecstasyがこの状況を変えられれば、と思うのです。

インタビュアーについて

Cameron Purdy氏は11xの開発者で、プログラム言語Ecstasyの開発者のひとりです。Oracle Coherenceの開発者のひとりでもあります。現在はxqitz.itの創業者兼CEOです。以前はTangosolの共同創設者兼CEOで、Oracleに買収された後はシニアバイス・プレジデントとしてエンタープライズJava、WebLogic、Coherence、Traffic Director、Exalogic製品を担当していました。Java言語と仮想マシン仕様のコントリビュータでもあり、Portable Object Format(POF)の著者でもある氏は、分散コンピューティングやデータ管理に関する特許も多数著しています。

この記事に星をつける

おすすめ度
スタイル

BT