Skip to content

Latest commit

 

History

History
1550 lines (1262 loc) · 164 KB

programmingEnvironment.md

File metadata and controls

1550 lines (1262 loc) · 164 KB

概要

まず思想とは「世界はこうあるべきだ」というような主張であったり、何か普遍的なアイデアや価値観を説くものです。 もし世界が最も合理的な技術や概念を採用して正しく成長していくと信じるなら、正しい思想を考えれば未来が分かります。

それで、これは私がTenyuプロジェクトのソフトウェア構成(どの言語、フレームワークを使うか等)の判断をする時に、あらゆる潜在的な可能性をも考慮して最も優れた判断をしようとして考えた諸々の着眼点や解釈、可能性などです。 「世界はこうあるべきだからこの技術はこう変わるはずで、ならばこの技術を採用するのが正しい」というような論理でソフトウェア構成を決めました。 その他雑多なメモも含まれます。

例えば、新しいコンピューターやOSの出現を促すために世界的にさらにクロスプラットフォームを追求すべきという考えが強くあり、この文書はその観点が強く出ています。特に重要なアイデアはfat_java_案です。

License

この文書はTenyuLicenseで公開されます。 用途制限:本ライセンスはp2pソフトウェアまたは創作活動のプラットフォームを作成する目的ではない場合にのみ適用される。

目次

バーチャルプラットフォーム_語の追加_整理

まず、クロスプラットフォームは現在存在する複数のプラットフォームで動作するというだけで条件を満たします。 そしてバーチャルプラットフォームは仮想環境にのみ依存しているという条件を指し、その仮想環境さえ提供されればどんな環境でも動作するので、その意味で未知のプラットフォームでも動作させやすい性質があります。

クロスプラットフォームなソフトウェアは内部にネイティブコードを含んでいて未知の環境で動作させれない可能性があります。環境毎のネイティブコードを実行時環境に応じて切り替えて使用している場合があります。それでもクロスプラットフォームに該当します。

バーチャルプラットフォームという語はpure javaとほぼ同じ意味ですが、とはいえjava以外でもバーチャルプラットフォームなソフトウェアはありうるので、pure javaという語はjavaコードにしか使えないのでバーチャルプラットフォームという語を使っています。

バーチャルプラットフォームなソフトウェアはコンピューターやOSの変化に強く、様々なOSの元で実行されるP2Pプラットフォームに適します。 そしてハードウェアやOSの変化を促します

誰かが新しいプラットフォームを作るとします。例えば新しいCPU命令セットを。 新しいプラットフォームはソフトウェア資産において古いプラットフォームに負ける可能性が高いですが、もしバーチャルプラットフォームなソフトウェア資産が多数あれば、その仮想環境のランタイムさえ実装すればそれらを全て活用できます。

javaはある程度そのような事を実現しうるプラットフォームですが、一部のjavaライブラリはネイティブコードを含んでいて新しいプラットフォームがJDKを実装しても動作しません。 典型的にはそのようなソフトウェアはwindows, linux, macなどのメジャー環境毎にネイティブコードを持ち、環境に応じて使い分けています。 後述するfat java案はそのネイティブコード同梱問題を解決します。

クロスプラットフォームと呼ばれるものの詳細な分類

  • バイナリレベルの限定的な互換性。ネイティブコードを含むJVMライブラリなど。多くの環境に対応していて、未知の環境に対応していない。
  • バイナリレベルの完全な互換性。pure javaなソフトウェアなど。これがバーチャルプラットフォーム。JDKさえ実装されれば完全に動作するので未知の環境にも対応している。
  • ソースコードレベルの限定的な互換性。ソースコードを様々な環境に向けてビルドできる。C言語のifdefを使って様々な環境に対応するなど。
  • ソースコードレベルの完全な互換性。コンパイラ等が実装されればあらゆる環境でビルドできる。クロスプラットフォームなマナーで書かれたC++プログラムなど。

バーチャルプラットフォームなソフトウェアのためのランタイムが持つべき特徴_案

ここでランタイムは仮想環境を実装したソフトウェア。

  • 中間コードでアプリをバイナリ互換にする。CPUやOSの変化からソフトウェア資産を守る。
  • 中間コードからLLVM IRへのJITを持つ。
  • 第三者による実装がライセンス上可能である事。新しいプラットフォームを作る人がそのプラットフォーム版のランタイムを自由に作成して配布できる事。
  • 可能な限り優れた移植性。新しいプラットフォーム向けに移植しやすい事。
  • 標準APIをハードウェアアクセラレーションする機構を備える。実行時環境がハードウェアアクセラレーションを提供していればそれを利用する。
  • 標準APIの強化(fat java案)やネイティブコード用ソースコードを実行時コンパイルする(JNI用実行時コンパイル案)で全アプリを完全にバーチャルプラットフォームにする。
  • p2pを主な領域として想定する。バイナリ互換が重要だから。dockerやソースコードレベルのクロスプラットフォームと比較した時、バイナリ互換の主張点はその領域しかない。p2pプラットフォームにアプリストアが構築され、バイナリ互換のプログラムが配布されるという事。

バーチャルプラットフォームなソフトウェアが充実した場合にもたらされるもの

  • ISAの多様化。RISC-V等
  • OSの多様化または移行

バーチャルプラットフォームなソフトウェアの増加を促すもの

  • アドインを扱うP2Pプラットフォーム
  • WWWを代替するプラットフォーム

ソースコードとバイナリ

誰かが別のOSに移行したいとします。現在使っているアプリがバイナリ互換であれば簡単に移行できます。 バイナリ互換ではなくソースコード互換のアプリもあります。 様々なプラットフォームに向けてビルド可能なソースコードからビルドされたアプリです。 しかしソースコード互換のアプリはエンドユーザーが新しいOSに移行するのを阻害します。 いちいちビルドしなおすか、誰かがビルドしたものを再インストールする必要があるからです。 バイナリ互換のアプリはプラットフォームの革新を阻害しないという点で最も創発的だと言えます。

さらにクラウドやP2Pにおいてバイナリ互換のアプリは適しています。 P2Pでは例えば誰もがネットワークに自作のアプレットを送信できるような仕組みが考えられます。 セキュリティは権限管理で対応します。

JITの強み

ハードウェアに新機能の実装を促せる可能性がある。32bitから64bitへの移行の時、C++アプリよりJavaアプリの方が高速な事例があったようです。JavaはJITを更新するだけでCPUの新機能を活用できるのに対して、C++アプリはアプリ毎に再ビルドと再インストールが必要です。 つまり中間コードとJITというアイデアはこの点でより創発的だと言えます。

仮想環境の強み_解釈

仮想環境の例はJDKや.NET Coreです。 一般にそのようなものはプロセス仮想機械と呼ばれていますが、私はアプリ側から見た印象で仮想環境と呼んでいます。極論すれば仮想環境はプロセス概念と関連付ける必要性がありません。極論ですがもしかしたら1プロセスの中に多数の仮想環境が作られるかもしれないし、多数のプロセスが協調して1つの仮想環境を作るかもしれないし、仮想環境がハードウェア実装されたり、カーネルの概念設計が全く変わってプロセスという概念が用いられなくなるかもしれませんが、どうなろうとも仮想環境のみに依存したソフトウェア資産は仮想環境が実現されたなら動作すべきです。

良く言われる仮想環境の強みは実行ファイルのバイナリ互換です。 もう1つはサンドボックス適性です。機械語プログラムでサンドボックスをやるにはVMware等システム仮想機械が必要です。

私は他にも重要な特徴がある事に気付きました。仮想環境はアプレット適性が高い。 C++等のネイティブコンパイル言語と比較した場合、仮想環境言語は任意の人が作ったアプレットやアドインを省メモリかつ高速に実行できます。 アプレットとはアプリ上で実行されるアプリです。アプレットの例はJavaアプレットやFlashやwasmです。 Webブラウザの考察の方でも書きましたが、例えばもしWebブラウザがJavaベースで作られていたらJavaアプレットの起動は高速だったはずです。WebブラウザがC++ベースで作られている時点でJavaアプレットに限らずWebページ上で実行されるプログラムのために仮想環境を起動する必要があります。その仮想環境が高機能であるほど起動時間が問題になります。WebブラウザをC++で作るという判断がアプレットに適していません。ホストアプリとアプレットが同じランタイム上で実行される方が省メモリになります。 任意の人がプログラムを加えれるプログラム、つまりアプレットやアドインに対応したアプリは仮想環境言語で作られるべきです。

アプレットからホストアプリに自由にアクセスさせないようにする必要があります。 ホストアプリが仮想環境言語で作られていた場合アプレットがその内容にアクセスしやすくなりセキュリティ上のリスクがあります。例えばアプレットからホストアプリのグローバル状態にアクセスできるかもしれません。 しかしホストアプリは一部の状態や機能をアプレットに提供したいかもしれません。 この点でアクセス可能なパッケージを制限する必要があり、Java9+以降のモジュールか、私が勝手に考えている1プロセス上で多数のJavaアプリを実行する疑似カーネルの仕組みが必要になります。 疑似カーネルの場合、アプレットは疑似RPCでホストアプリとやり取りします。

仮想環境言語とシステムプログラミング言語_案

仮想環境言語とシステムプログラミング言語という組み合わせは究極的にも有力だと思っています。 仮想環境言語はあらゆる環境で共通の機能を使用できます。例えばJavaはJDKという一種の仮想環境を想定した言語です。 システムプログラミング言語は環境固有機能を使用できたりフリースタンディングできます。例えばCです。 システムプログラミング言語はコンピュータに対するほぼ完全な制御性を持つという特徴から仮想環境の欠点を補える。仮想環境はどの環境でも出来る事しかできません。だから仮想環境は1つシステムプログラミング言語を想定し連携すべきです。 このアイデアはコンピュータをプログラミングするという問題に対する根本的な解決のフレームワークの一部です

fat_java_案

JDKにAPIを追加しまくれば、それらはネイティブ実装されるので、ユーザーライブラリがネイティブコードを同梱する必要性がほぼなくなるだろうというアイデア。 jvmライブラリでネイティブコードを同梱しているものを広く調査して、JDKにそれらネイティブコードを代替するAPIを実装する。 そのJDKの肥大化によってほぼすべてのjvmライブラリをpure javaにしようというアイデア。 APIはライブラリのを直接持ってくるのではなく、できるだけ汎用的にする。その主な方法はステートレスにする事とフルパラメタライズする事。 "新しいコンピューターアーキテクチャを作る人がJDKさえ実装できればほとんどのJavaアプリが動く"という状況を作るのが理想。

このアイデアの良いところは、Java世界でどんなネイティブAPIが必要とされているかが既存のライブラリによって洗い出されている事にある。 性能的にもメリットがあるはずで、JNIでネイティブコードと連携するとオーバーヘッドがあるが、JDKに実装する事でそれを無くせるはず。

JNI用実行時コンパイル_案

JNI用のソースコードをJarに含めて実行時コンパイルする事でソースコード記述時点で存在しない環境にも対応しようというアイデアです。 とはいえ、JDKが最終的にJNIに期待するのは環境固有機能の使用だろうと思います。性能目的でのJNI使用は多数実在していますが、JITとfat java案で解消できるはずだから、最終的には環境固有機能、特に特殊なハードウェア機能の利用がJNIの役割になるはずで、結局JNIを使用するコードはバーチャルプラットフォームにならない可能性が高い。環境固有機能を呼び出すコードはどう努力しようともその意味によって環境依存します

実行時コンパイルするとして、JNI用のコードをどの言語で書くべきか?

C案。 Cコードをjarに同梱し、JDKにCコンパイラを同梱し、実行時コンパイルする。Javaと相補的という意味ではCの方がC++より合う。学習コストが低い。コンパイル時間が短い。

  • Cは静的解析ツールがあるので移植性が無いコードを排除できます。
  • Cコンパイラの普遍性
  • コンパイル結果はどうせJDKのJITが効かないのでキャッシュしておく。

LLVM案 OSがLLVMを標準搭載するという前提で、それを使ってコンパイルする。この場合jarに同梱されるJNI用コードはどの言語でもいい。

JNI用コードは最終的に環境依存するものだが、やはりjarに同梱してソースコードを実行時コンパイルする方が変化に強くなる。 例えば命令セットの変化に強くなる。

C言語は代替されるか_比較_考察

Cで書かれたプログラムは脆弱性が多かったり保守性が低いので代替が望まれます。 しかし、Cはあらゆる言語の中で最も膨大かつ基礎的な既存資産を持ち、膨大な実績があります。 さらにCコンパイラの普遍性やコンピューターの完全な制御性からCは最も使用されるシステムプログラミング言語です。

Cの代替が不可能と感じる一方で、他の言語からCへのトランスパイラはアイデアとして優れていると感じます。 何か他の言語を作り、そこからCにトランスパイルできるようにすれば、即座にあらゆる環境でその言語は機械語へコンパイル可能になります。さらに今後出現する未知の環境においてもCコンパイラは恐らく作成されるので、未知の環境でも機械語へコンパイル可能になります。

  • Cコードは機械語と単純に対応づくので機械語にコンパイルできるならCコードにトランスパイルできる。
  • Cコンパイラの普遍性からCへのトランスパイラは価値が高い。
  • 環境非依存のコードを作成し、Cへのトランスパイルのタイミングで環境依存させれる。
  • より大規模開発に適した言語仕様を提供できる。

しかし、カーネル等ハードウェアに近い開発では単にCの言語仕様がハードウェアの動作や状態をイメージしやすく優れているという意見があります。 Cは静的解析ツールが多数あるので他の言語が上回るのは簡単では無さそうです。

さらに、LLVMはこのアイデアの上位互換となるものを既に実現しています。 LLVMは様々な言語からCコードや機械語やIRを作成できます。

C++はCを代替するための良い条件を満たしているように思いますが、Cを置き換えていません。 C++の学習コストの高さ、言語仕様の複雑さから生じるプログラマー毎の設計方針の食い違い、そしてCの単純な言語仕様が適している領域がある事が原因だと思います。 詳細なメモリ管理やタイミングなどコンピューターを完全に制御したい場合、抽象化の上では逆にやり辛い。 コンピューターの動作や状態をプログラマーが意識しながらコーディングできること、大人数の開発でも一貫してそのようなコードしか書かれないこと。それらを考慮するとC++よりCの方がハードウェアに近い領域では適している可能性が高い。

ZigはCを代替するか? 恐らく代替しません。

  • Cの脆弱性の多さは恐らく静的解析ツールによって大部分解決されます。
  • Zigの性能と保守性はCと大差無いだろうと思います。

Nimは微妙にCにもC++にも勝てなくて使用領域が無い。

  • NimはGCつきのシステムプログラミング言語ですが、恐らく静的解析ツールが付随したGC無し言語の方がシステムプログラミング言語として優れています。GCは一部の開発では邪魔になります。
  • 一貫してCの方がハードウェアの動作をイメージしやすいコードが書かれる。以上からハードウェアに近い領域でCに勝てません。
  • 抽象度が高い言語は、CにトランスパイルするよりC++のように直接機械語にコンパイルする方が最適化の余地が大きいので、Cトランスパイラ言語のNimはC++に性能で勝てないだろうと思います。
  • Nimは高度かつ複雑な言語仕様によってプログラマーの均質化に失敗しそうです。

それで、Cは代替されるか?私の考えはこうです。 LLVMによって各種言語からCへのトランスパイルが可能になり、成熟したC++があるし、最新のRustがありますが、いずれもCを置き換えていないという事実がある。そして静的解析ツールがあればCの脆弱性を克服できる事から、今後もCは代替されません

言語とは何か_解釈

言語は処理系や言語仕様や開発ツールも含み、どの部分もバージョンアップされていく。 それを構成する全部分が更新可能でもそれ自体が存在する。 例えばオブジェクトの全メンバーにセッターがあり更新したとしてもそのオブジェクト自体は変わらず存在し続けているように。 活動の連鎖性みたいなものがそれを捕捉させる。 JavaとかPHPとか言語の名前が意味しているのはそれ。

言語と言語仕様は良く混同されているが区別すべき。 例えば言語という言葉で言語仕様を指して「言語で性能が決まるわけではない」という言説がたまにあるが、ランタイムやコンパイラをも含んで言語と呼ぶべきなので、言語は性能に影響する。 候補となるランタイムやコンパイラが複数ある場合もあるが、それも含めて様々な事を念頭においた文章を書くしかない。

何が言語の趨勢を決めるか_期待説_解釈

エコシステムから言語への期待の発生、言語仕様や処理系がエコシステムからの期待に応えて成長する、他プロジェクトへの期待の伝染と採用の広がり、そのような活動が言語周辺のエコシステムにある。その活動が繰り返される限り言語は広まる。言語の流行りや廃りはそのような活動によって決まります。

各言語はそのソフトウェアエコシステムから何らかの期待を受けています。 Javaエコシステム、PHPエコシステム、Cエコシステムなど、それぞれ言語への期待が違います。 クロスプラットフォームであれ、ライトウェイトであれ、フリースタンディング可能であれ、など。 期待は言語側が自称する特徴や実際に実現されている特徴と必ずしも一致しません。とはいえ人々はバカではないので、期待は概ね実体と一致します。

言語は期待に応じてアップデートされます。そうしなければエコシステムと軋轢が生じます。 新しいプロジェクトが言語を選定する時、必要な特徴を持つ言語を探しますが、完全な確認をせずせいぜい評判や実績を調べるだけです。だから言い換えれば期待が伝染します。 同じ期待を持つプロジェクトがその言語を採用するとその言語のアップデートの方向性が規定されます。

http://readwrite.jp/develop/13680/

「古いジョークに、エンジニアが今後30年間使われる言語は何かと聞かれて、分からないけどそれでもそれはFortranと呼ばれてるだろう、と答えたというのがある。息の長い言語は、70~80年代にデザインされたものと同じではない。多くの場合、人々は言語から何かを引くことはないが、足すことはある。そうすることで後方互換性は損なわれずに問題が修正されるからだ」

Fortranは非常に古い言語で、科学技術計算の期待に応え続けてきたという事になると思いますが、時代によって具体的な要求は様々だったと思います。言語はエコシステムからの期待に応えるためにアップデートされ、変化し続けます。

言語は一部の期待を捨て去る場合があります。 近年のメジャー言語でも後方互換性が捨てられた場合があります。 例えばJava AppletはJava11で廃止されました。これまでいくつものAPIがdeprecatedないし廃止されました。Python 3.0は後方互換性を捨てました。JavaでWebフロントエンドを作っていた人達が居ましたが、もはやJavaにそれを期待する事はできません。つまりJavaはある種の期待を切り捨てたのです。OpenOfficeなどWeb以外でもJavaアプレットを使っていたソフトウェアが存在するようです。 Javaアプレットを使用している人達が多ければ切り捨てられなかったはずです。 つまりその言語が現時点で何を実装しているかよりもその言語にどのような期待が集まっているかが本質です。

DやNimなどたまに言語仕様が優れていると評価されるのに流行しない言語があります。

  • 実際のソフトウェアプロジェクトから期待されていない。言語マニアの注目を集めているだけ。
  • 将来のアップデートの方向性や想定する利用者を言語側が宣言していない。
  • 既存言語と同じ利用者層に訴えかけている。実績が無い言語は期待を奪えません。新興言語は独自の期待を得る事が鍵です。

結局、言語の趨勢を決めるのは期待です。PHPという成功例がそれを示しています。

各言語への一般的期待_解釈

Javaはクロスプラットフォームという期待を受けています。公式の処理系や言語仕様だけでなく、Java周辺のエコシステムが作るライブラリはクロスプラットフォームである事が多く、そうでないなら明記されるだろうと思えます。 ライブラリの豊富さやJDKの質についても期待されます。恐らくJavaが流行した理由は仮想機械+中間コード+JITという構成で高度なクロスプラットフォームを実現するという独自の期待を得た事、そして期待に応え続けた事です。

C言語はコンピューターの完全な制御そこそこの移植性コンパイラを書きやすい事を期待されています。

C#は後発言語としてbetter javaであること、MSの構想で良くサポートされたりMSの開発力によって高水準が維持されるだろうと思います。

PHPは手早くウェブサイトを作れる事を期待されていました。PHP: Hypertext Preprocessor この名前はそれが何であるかを示しています。それは当時独自の期待だったと思います。 PHPはいくつかのDBを標準でサポートしています。例えばmysql_query()という関数が定義されていました。それはとてもPHPらしいことで、汎用性を重視するプログラミング言語はそのような事をしません。 PHP対応したレンタルサーバがたくさんあり、誰でも簡単に動的なWEBサイトを作れました。そのようなエコシステムもPHPらしいことです。

JavaScriptはWEBフロントエンドが期待されます。近年ではサーバサイドでも使われます。 ちなみにJSやTSはWebAssemblyによって殺されるか?恐らく殺されない。他の言語のエコシステムはWebフロントエンドのために成長する意欲をほとんど持っていない。しかしC++が進出してくるかもしれません。そもそも私はwasmの行方にまだ懐疑的です。

Python。 業務の細かな場面で使われる利用者数が限定的なアプリがPythonで作られる。 Pythonは機械学習に使われますがそのコアな部分はネイティブコードを含むライブラリで処理します。 Python+ネイティブコードという多言語連携でPythonのちょっとしたアプリを作る適性と高速な機械学習を組み合わせる事に利点があるのだろうと思います。例えば、WebスクレイピングとかWebサイトのDBから取得したデータからAIで抽出したデータをサーバに自動登録するあるいは誰かにメールするとか。利用者数や利用頻度が限定的な業務アプリに適している。

Nim。流行っていません。「効率的で表現豊かで美しい言語」。それを語られてもどのプロジェクトがこれを採用すればいいのか分かりません。Nimに欠けているものはターゲット層を明確にする事です。

何が言語の趨勢を決めるか_歴史説_解釈

いくつかの言語は既存の言語よりスマートにコードを書けるなど言語仕様上の細かなメリットを主張し、既存の言語を代替するために登場しました。例えばkotlinはbetter javaとして登場しました。 しかしそのような言語は多くの場合既存の言語を代替しません。

多くの専門家が新興言語の方が優れていると説明してもなかなか代替は起きません。なぜか?

  1. 既存言語もバージョンアップで言語仕様を改良できるから。
  2. 細かな改良でいちいち言語を乗り換えていたらキリがないから。
  3. 僅かなメリットのために新しい言語を覚えるのが嫌。
  4. 抱えているプロジェクトが既存言語で書かれている。

特に2について。エコシステムが軽率な理由で言語を乗り換えるなら小さなエコシステムが乱立する事になりどのエコシステムも十分なソフトウェア資産を持たなくなりライブラリの量やプログラマーの調達に苦労するようになります。だから既存の主流言語が改良されるのを待つという判断は全体利益に適います。
私はJavaを学び始めた時知り合いのエンジニアからkotlinを進められましたが、それでもJavaを選択しました。新たに言語を学ぶという段階でもより優れた新興言語ではなくJavaを選びました。さらに、Javaを学ぶ前にC#を使った事があり素晴らしい言語だと思いましたがそれでもJavaを選びました。Javaはクロスプラットフォームな実行バイナリを作れるプログラミング環境として標準的で、恐らく歴史的に最初にそのコンセプトに取り組み実現しました。僅かなメリットのためにJava以外へと移るようではエコシステムの安定が得られず全体利益を損ねるのでその態度に疑問を感じたからです。私は歴史的理由からJavaを選択しました。

インタプリタ_解釈

昔インタプリタがスクリプトを実行時環境で解釈する事でクロスプラットフォーム性が高まるという観点がありましたが、中間コード(Javaバイトコード等)を実行時環境でJITするという方式は上位互換であるように思います。 強いて言えばソースコードを配布する方式は実行時環境でエンドユーザーがソースコードを確認、修正しやすいかもしれませんが、実際そのような動態は生じそうにありません。

WebAssemblyとJVMが今後衝突する可能性_メモ

  • WebAssembly
    セキュリティ◎
    性能◎
    クロスプラットフォーム〇
    汎用目的△?
    多言語〇
    ブラウザではより厳しいセキュリティが要求され、機能は制限されます。
    セキュリティは計測不能な対象であり見解が分かれます。ブラウザ毎にセキュリティに関する見解が異なる可能性があり、互換性に限界が出る可能性があります。ブラウザ間の互換性問題があるかもしれないという点でクロスプラットフォーム〇に。
    汎用目的はWASIプロジェクト次第なので?つき。

  • JVM
    セキュリティ△?
    性能◎
    クロスプラットフォーム◎
    汎用目的◎
    多言語〇
    ブラウザのサンドボックスに比べればJVMはリスクがある。
    しかし、だからこそソースコードを公開するプロジェクトと相性が良い。
    実行時にリポジトリにアクセスしてソースコードが公開されているかを確認するシステムが確立すればセキュリティ面は改善する可能性がある。後述するセーフランチャーのようなアイデア。
    JVMはバッファオーバーフローなど不意な脆弱性を生み出してしまうリスクは小さいので、問題となるのは悪意あるコードを排除できるかです。開発者の信用評価をするシステムもJVMにとって重要です。
    後述しますがシリアライズされたオブジェクトを送受信するシステムがWWWを置き換える可能性があり、
    Javaはそのようなシステムを記述するのに適した言語の1つです。

仮想デスクトップによるreproducible_builds証明_案

このような機能があればreproducible buildsを証明できそうです。 githubが仮想デスクトップを提供し、開発者がそこでビルド手順を実行し、 その模様を記録し、作成されたバイナリを入れるフォルダがありそれがリリースに置かれる。 その操作の模様と結果をgithub上に表示する。

自己完結型の否定_批判

Java9+では自己完結型が推奨されるようです。自己完結型はバイナリ互換性がありません。 https://aoe-tk.hatenablog.com/category/Java

Java 11ではPublic JREが本当になくなりました

一応Java 11以降でもOS側JDKはありえます。Liberica JDKがJavaFX+MSIインストーラーを提供しています。 しかしLibericaは潜在的な可能性のための最後の配慮であり、現在のJavaでは自己完結型が推奨されているという印象があります。

しかし自己完結型が主流になりバイナリ互換を失えばJVMを使用している意味がありませんC++とQtのように仮想機械無しでソースコードレベルのクロスプラットフォームを実現した言語がありますが、それに対して自己完結型の主張点は何か? GCやバッファオーバーフローが起きにくいといった事を主張してみても、静的解析ツールである程度補えるし、GC強制言語でソースコードレベルのクロスプラットフォームを達成する事も可能です。 JITによる実行時情報の活用があるものの、ほとんどの場合C++の方が高性能です。 要するにJVM等の仮想機械を採用する理由はバイナリ互換以外無い。 ネットを検索するとJVMは偉大であるという評価が良く出てきますが、Java9+以降の自己完結型の流れによってその存在意義は揺らいでいます。

現状Java9+はあまり使われていません。多くのプロジェクトがJava8に留まっています。 https://snyk.io/blog/jvm-ecosystem-report-2018/ 少し前のデータですが、Java9+全体でJava7未満です。Java8には到底及びません。 こうなっている理由はいくつか考えられます。 ・Java9-10が短期サポートしかない。Java11を待っている。 ・単に時間が足りてない。いずれJava9+にする。 ・Java9+への移行作業が苦痛。自己完結型を求めていない。使用しているライブラリがJigsawに対応していない。 https://qiita.com/kazumura/items/50f041054572ceffe994 >(B) JPMS(Jigsaw)の否定

このページのグラフによると将来使用するバージョンにおいてすらJava8はJava11並に多い。 Java11の方が様々な面で改良されていると期待されるにも関わらずそうなるのは、Jigsawがそれだけ嫌われているという事です。 Jigsawは自己完結型を推進する仕組みです。

依然Java8が最も多いものの、僅かに減少し、Java11の採用が増えてきています。 https://qiita.com/kazumura/items/46c5b99a9ff422f2eb45

バイナリ互換の放棄はJavaの技術的特徴を失わせます。 しかし、実はJavaの方針にバイナリ互換は入っていません。 https://en.wikipedia.org/wiki/Java_(programming_language)#Principles portableはソースコードレベルの移植性を意味します。 Javaの基本方針からの逸脱は無い、という事です。 自己完結型はinterpretedかつportableでありながらバイナリ互換を壊します。
しかし、やはりjvmの存在は実行バイナリのクロスプラットフォーム性を意味するもので、Javaがエコシステムに期待させたものです。
P2P領域でバイナリ互換のプログラムが必要とされるし、特にアプレットを自由にP2Pネットワークに流すようなシステムがWWWを置き換える可能性があり、Javaは実行ファイルのクロスプラットフォーム性を維持すべきです。

私は、非自己完結型JVMの利点として、JVMが実行時にアプリを切り替えるという潜在的な可能性、その他アプレット適性、p2p適性等について書きました。

Java8_OS側JDKの必要性_解釈

corretto/corretto-8#108 私はJava環境がこのようになることを期待しています。 2つのJavaが共存すべきだと思います。OSサイドのJava8JRE+自己完結型の最新JRE。JigsawはJava9+を自己完結型にするのに適している。下位互換性は、OSのJava8JREによって維持されます。自己完結型のアプリケーションは、JREの脆弱性を残す可能性が高くなります。OS側のJREが存在する必要があります。下位互換性のためにはJava8でなければなりません。いくつかの有名なプロジェクトはJava8からJava9+への移行に苦労したり失敗したりしている。私の考えが正しければ、Java8のjreインストーラとアンインストーラは将来永久に必要になると思います。

Java9+は後方互換性を簡単に捨てるようになったと思います。 バイナリ互換のクロスプラットフォームも失いました。

それで私は2つのJavaが併存する事を主張しました。 Liberica JDKがOS側JDKとして適していると思っています。

kotlinとjava_メモ

私はjme3を使う事を考えていて、jme3 sdkはnetbeansベースで、netbeans+kotlinのプラグインはプロジェクトが停止しています。 JetBrains/kotlin-netbeans#122

javaはnull安全がありませんが静的解析ツールで補えます。

Glb

TenyuはGlbという特殊なクラスを使用しています。
https://github.com/lifeinwild/tenyu/blob/master/src/main/java/bei7473p5254d69jcuat/tenyu/release1/global/Glb.java

私のおぼろげな記憶によれば、これは昔某社で見かけたアイデアであり私の発想ではありません。 Glbはプロセスにただ1つのクラスで、グローバル状態を管理し、インスタンスが作られずstaticメンバーで構成され、特殊な仕組みは一切なくとても単純なものです。 グローバル状態への批判は非常に強いのでGlbは批判されそうですが、実際どうだったか。

  • テストは非常にしやすい。セッターでテスト用インスタンスをセットするだけで実行時環境をテスト用にできます。 テスト用クラスは本番用クラスを継承して一部メンバーをオーバーライドするだけです。
  • Glbはトランザクションが必要な場合があります。 その領域はSoftware Transaction Memoryと言われているようです。 ClojureがSTMを実装していますが性能が悪いようです。 STMは根本的アイデアとして十分に解決されていない。
  • Glbは構文にとって最も素直な方法で扱う事ができます。
  • アプリのあらゆるクラスがGlbに依存する可能性があるので、もし一部のクラスを他のプロジェクトと共有する事を考えた場合、問題になります。後述します。
  • Glb的アイデアを推し進めると階層型オブジェクトという世界観でシステムを捉えれるような気がしてくる。staticメンバーはクラスローダー内で一意になりますが、Glbのstaticメンバーはそのクラスローダー空間を1個のオブジェクトとみなした場合のメンバーである、というような。一般にオブジェクトのメンバー変数がメソッドから可視でありそのクラス内の標準知識であるように、Glbのstaticメンバーはそのクラスローダー空間で可視であり標準知識という事。
  • Glbをデフォルトパッケージに置いて、かつそのstaticインターフェースについて共通規格化すると、Glbに依存したクラスを他プロジェクトで再利用可能になる。

Glb的アイデアを主張している人が他にいないか探しましたが、こんな記事を見つけました。https://www.ibm.com/developerworks/jp/webservices/library/co-single.html

Glbはオブジェクトであるべきか_考察

現在の実装ではGlbは純粋にstaticでありインスタンス化されません。 もしGlb自体がオブジェクトだと、Glbの外側のロジックが出現します。 Glbをオブジェクト化する場合、Glbをメソッドの引数に入力しローカル変数として扱う場合が出てきます。 恐らくそれは問題を引き起こします。
Glbと名付けられたものがLocalになる事は意味的な間違いがあります。

Glbに依存したクラスを他プロジェクトから使う_メモ

Glbはいくつかsetup系メソッドを持ちます。 setup系メソッドはGlbのstaticメンバーを初期化しますが、 どのメンバーを初期化するかがメソッド毎に異なります。 例えばテストケース用に一部のみ初期化するメソッドがあると便利です。 あるいはGlb依存クラスを他プロジェクトから使用する場合、 他プロジェクトから呼び出しやすいsetupメソッドを用意する必要があります。 その場合設定ファイルの配置等をしたうえでsetupメソッドを呼び出す必要があります。

多くの場合、プロジェクト間でのクラスの共有はあるプロジェクトがデータを作成して他のプロジェクトはただそれをデータとして読み取るだけです。 つまりクラスの全機能が使える必要は無く、ゲッター以外要りません。 Glb依存は多くの場合複雑なメソッドで生じ、メンバー変数の初期化やゲッターでは生じないので、そのような条件を満たせばGlb依存していても問題無く利用できます。 Javaの実行において、依存したクラスのロードはそれが必要になるまで行われません。 つまりゲッターを使うだけならGlb関連の依存関係を解決する必要はありません。

実際、その動作をテストしました。

  • クラスA,B,C
  • Aはメソッド部でBに依存、メンバー変数でCに依存
  • Aをシリアライズしてファイルに保存、Bのクラス定義を削除して次のテストでファイルを読み込みデシリアライズ。 結果:デシリアライズしてCにアクセスできるが、Bに依存したメソッドは実行できない。

さらにテストしました。 メンバー変数の初期化に他クラスのstaticメソッド等を使用していて、デシリアライズの段階でそのクラス定義が無かったら、 どの範囲まで動作するか? 結果は、デシリアライズ自体が失敗しました。 デシリアライズは初期化処理を呼ばない事が可能に思えますが、 少なくともKryo5 RC1では初期化処理を呼び出そうとして失敗しました。 デフォルトコンストラクタを呼び出した事でメンバー変数の初期化が行われた結果だと思います。 しかし、初期化処理で間違った値が設定されたとしてもその後デシリアライズ処理の中で正しい値が設定されるので、 初期化処理が動きさえすればそれが無意味な値を設定してもその後に正しい値が設定されます。 これもテストで確認しました。 多くの場合、メンバー変数の初期化処理でGlbに依存するとすれば定数か設定ファイル系なので、 そのようなクラスがnullでも良いから返して動きさえすれば、メンバー変数の初期化でGlbに依存しても多くの場合問題ありません。

Glbに依存したクラスを他プロジェクトから共有する事は留意する事が色々あります。 とはいえ、Glbを使わないコードでも同様の苦労があるはずです。

最高のプログラミング言語は_考察_案_解釈

このような事をかなり多くの人が思うだろうと思います。 「私の長期的なプログラミングライフに適した最高のプログラミング言語は何ですか?」 あるいは「IT企業としての長期的活動に適した社内標準語とすべき最高のプログラミング言語は何ですか?」

この問題の本質は何か?

  • 学習時間を無駄にしたくない。長期サポートされる開発環境が理想です。言語によってGC等処理系の前提の違い、言語仕様上の概念の違い、周辺のライブラリやフレームワーク等の違いがある。最新の話題をキャッチアップしていく必要もある。だから言語習得は学習コストがかかります。他の言語への乗り換えはそれまでの学習時間を無駄にする可能性があります。「その都度ぐぐって使うから何も事前に習熟しておく必要が無い」という主張はある程度正しいものの限界があります。運よくいつも全ての必要な情報を検索で見つけられるとか、見つけた情報をすぐに理解して活用できるかという点で楽観し過ぎです。「その時々の問題を解決できる最も簡単な言語を選ぶ」というスタンスは、長期的に様々な問題を扱っていく場合、毎回異なる言語を選ぶ可能性があり、それなら最初学習コストを払ってでも本格的な言語を覚えて一貫して1つの言語で解決する方が結果的に楽かもしれません。
  • できるだけ可能性が広いスキルセットが欲しい。その方が何かを作ってみようと思い立つ可能性が高くなります。あるいは、やってみようと思った事を何でもやれるようになります。
  • 世界のソフトウェアエコシステム全体で重複したソフトウェアを作らないように。もし最高のプログラミング言語が明らかになり世界がそれに統一されたら重複したソフトウェアを作る労力を省けます。現状、各言語毎にほとんど同じ内容のライブラリが作られています。
  • コンピューターをプログラミングするという問題に対する解決のフレームワークはどんなものか。つまりプログラミングとは根本的にどんな問題で、どんな枠組みで解決されるものなのか。例えば仮想環境言語+システムプログラミング言語というアイデアはその一種です。つまりその都度自分の状況に応じて適切な言語を考えるのではなく、プログラミングとは何かという事に対して抜本的な解決の枠組みを見出せたなら、ただ1つの最高のプログラミング言語または最高の言語の組み合わせが見つかるはずです。

だから最高のプログラミング言語を考える必要があります。

一般論として、やろうとしている事に応じて選択する事が重要だと言われます。 ではどんな事にどんな言語が適しているか?そしてその理由は?

どんな領域があるか?主に使用される言語は?

  • OS C
  • デバドラ C, C++
  • 機械語汎用アプリ C, C++, 科学技術計算ならFotran
  • 仮想機械汎用アプリ。バイナリ互換 Java, C#
  • スクリプト汎用アプリ。バイナリ互換 Python
  • Webフロントエンド JavaScript, TypeScript
  • 組み込み。実質、OSまたはデバドラまたは汎用アプリ。 C, C++, Java

どんな理由でそうなるか?なぜ1言語で全てをやらないか?

多くの言語でクラス概念が使用されるが、クラス設計が適さない領域がある。 MMO開発では、ゲームロジックという設計対象自体が常に奇抜な発想を求める不安定なものなので、クラス設計が適しません。interfaceすら安定しないほどの、まるで予測不可能な概念レベルの変化が生じる対象において、クラス設計は通用しません。 ちなみに、そこでECSという設計に希望を持つ人も居るようですが、私はECSは悪い設計だと思います。私はその問題について構成ベースの別の設計を思いついたので、近いうちにやってみようと思っています。 さらに、カーネル開発では、抽象的設計の上ではコードがどのようなハードウェアの動作を引き起こすのかイメージしづらく、抽象的設計は必ずしも好まれないようです。主要OSはほとんどCで書かれているようです。Linuxは一度C++に移行しようとしてまたCに戻ったそうです。Cはクラス概念を持っていません。さらにハードウェアの予測不可能な進歩によって抽象的設計はいちいち壊れます。例えばモバイルは消費電力に敏感で、memristorはメモリがプロセッサになります。

クラス設計が適した領域とは? ほとんどのアプリ。設計を作り込んでいけばやがて安定するだろうと思えるような設計対象。アイデアが変化しにくい対象。ハードウェアの動作を詳細にイメージする必要が無い場合。

少し古い記事ですがRustでOSを作った例について。 http://qwerty2501.hatenablog.com/entry/2017/03/18/224839 あまり良い結果ではなかったようです。C++がOS領域でCに負けている事も含めて、OS領域でCが特に適している事を示唆しています。 一方でC言語はほとんどのアプリ開発に適しません。部分的な関数をCで書くことは多々ありますが、アプリ全体をCで書くことはあまりないと思います。gitはCで書かれていますが恐らくそれはCで大規模プログラムを書くという特殊スキルを伸ばした人が作ったからです。 つまり領域毎に使用言語が異なるという状況は今後も変わりそうにありません。

クラス設計がプログラミングのほとんどの領域で猛威を振るっていますが、それにも関わらず構造体程度の概念しかないCがOSという最重要領域で生き残ります。つまり1言語による完全統一は実現しそうにありません。

言語によってプログラマーに標準的に期待できる事が違う

  • フリースタンディングなコードを書くスキルを最も期待できるのはCプログラマーです。
  • C++プログラマーは抽象的設計と低水準操作を両方扱います。扱う概念が多岐に渡るので、C++プログラマーは均質性がありません。
  • Javaプログラマーはクラス設計に慣れていて、他のパラダイムでコードを書きません。Javaプログラマーは均質です。

なぜあらゆる言語概念を搭載した言語はダメか? あらゆる言語概念を搭載した最強万能言語があったとして、学習コストが高すぎるのでその言語をマスターしている人は限られ部分的にしか使えない人がたくさんいる状況になるし、大勢で1つのコードベースを修正したらソースコードが部分毎に異なるパラダイムで書かれてしまいます。一人で書いたとしても書いていく中で新しい言語概念を覚えたらそこから使いだすわけで、コードに一貫性が無くなります。そのような問題は学習コストだけでなくそもそもどう書くのがベターかという判断の相違によっても引き起こされます。

問題を多言語連携で解決するというアイデアもあります。Pythonが機械学習ライブラリをネイティブコードに頼っているように。あるいはJavaがJNIでネイティブコードを利用するように。つまり1つの大きな問題を複数のプロジェクトに分けて、プロジェクト毎に言語を選ぶということです。 多言語連携の長所は、1プロジェクト内では一貫性があるコードが記述される事です。 多言語連携の弱点は言語間連携の部分で新たに留意する事が出てくることです。例えばJNIでは、Java起動オプションでGCを選択できますが、使用しているGCによってJNIの性能がアプリによって致命的なほど変わる場合があるようです。

性能や大規模開発適性を求めない場合がある。利用者数や利用頻度が限定的な、業務上必要とされるちょっとしたツールをスクリプト言語で作りたいという需要がある。

このような考えで「なぜ1言語で全てをやらないか?」について私は納得しました。 しかしまだ問題は続きます。最高の1言語を特定できないなら、最高の言語の組み合わせは何か?

  • 一般的な評価基準。実績、ライブラリの豊富さ、処理系の性能、解説記事等の豊富さ等。
  • 多言語連携前提なので1言語あたりの学習コストが低い事。

それで、私はJava+Cが有力だと思いました。 ところが調査を進めるとC++が恐ろしい可能性を持っている事に気付きました。 私の中で最終的にC++またはJava+Cという候補が残りました。

  • C++ C++は1言語路線の最有力候補。 学習コストが高い。 Qtでソースコードレベルのクロスプラットフォームも。 1つ恐ろしい可能性がある。C++はWebAssemblyでWebフロントエンドにも乗り込めるし、WASIプロジェクトの結果次第ではVMすら手に入れてバイナリ互換のクロスプラットフォームすら手に入れる。そこまでいくとJava+Cの対応可能範囲に追いつく。 今後C++は他の言語に対して本当にその領域でC++を退ける優れた特殊化を持っているかを問います。 JDKや.NET Coreや主要ブラウザ等はC++で作られている。重要なプログラムほどソースコードが大規模化し性能がシビアに要求されるのでC++で作られる。
  • Java+C それぞれが単純な言語で大抵の問題を片方で解決できて、ステップアップしやすい事、ソースコードの一貫性を保ちやすい事、そして連携させる事でほぼすべての問題に対応できる事を持ってこれらが最高のプログラミング言語であると考える。相補的。 いずれも長年最上位のメジャー言語。 JavaもCも学習コストが低い。両方を学ぶならC++と同じくらいだろうか。 仮想環境言語+システムプログラミング言語というアイデア。 他のJVM系言語のソフトウェア資産を利用できる。 null安全ではないが静的解析ツールで補える。 ちなみにGWTやteavm等があるもののJSより先にJavaアプレットがあった事を考えると妙な話だなと思います。 Java+CはWebフロントエンドをどうやるか?実はJavaベースのP2PソフトウェアがWWWを置き換える可能性があります。私は少なくとも技術的にはその方向性が有力と思っています。実際どうなるかは分かりません。しかしもしそうなるとWebフロントエンドという概念自体が無くなります。 javaバイトコードからLLVM IRへのJITができるとC++とそん色ない性能を出せるだろうと思います。1プロセスで多数のJavaアプリを実行する疑似カーネルという概念が実現されると性能でC++やCを上回る可能性があります。

C++とJava+Cの比較は難しいです。いくつか思ったことを書いておきます。

  • JDK自体はjavaで実装できない。一部モジュールはJavaで実装できるが。
  • Webブラウザのようなアプレットを扱うホストアプリは別項目に書いたように仮想環境言語で書いた方がアプレットの起動が高速になり総合的に省メモリになります。このようなものでは本来Javaが優れています。
  • 戦闘機システム等のラグが許されないソフトウェアではjavaはgcのラグが問題になるかもしれません。それとたぶんJNI連携が多発するので何かソリューションが必要です。

当初私はプログラミング言語の未来についてこう考えていました。 バーチャルプラットフォームなソフトウェアが増える事によってプラットフォームの進歩が激化したり多様化すればC++を含むネイティブコンパイル言語のソフトウェア資産はついてこれないと。 ソースコードレベルではCトランスパイラがあればついていけますが、実行バイナリがバーチャルプラットフォームではないので、再ビルドと再インストールの手間があるから徐々に使われなくなっていきます。 例えばCPU命令セットが急激に多様化した場合、PCを買い替える時アプリを移行できるかということです。アプリがビルドされる時点で存在していなかったCPU命令セットには対応できません。しかしバーチャルプラットフォームソフトウェアはランタイムの更新だけで対応できます。1つ1つのアプリについてリビルドや再インストールが必要なのに対し、ランタイムの更新だけで済むということです。 だから長期的にはバーチャルプラットフォームなソフトウェアが利用者を増やすのだろうと思っていました。 しかしWASIの結果次第でC++アプリもバーチャルプラットフォームになるので、この話は成立しなくなり、最高のプログラミング言語が何であるかという問題は再びはっきりしなくなります。 しかし一言語路線の弱点は、その最有力候補であるC++がOSを記述する言語として採用されていない事です。

ちなみに私はJava+CにさらにTypeScriptを加えようと考えましたが、止めました。Web技術の行方に疑問を持っているからです。JSやTSはwasmによって殺される事は無いと思いますがそもそもWWWがこける可能性が気になる。 TypeScriptは主にWeb系で使われ、他の言語よりバグが少ないかもしれません。使用される分野が限定的だからかもしれません。JS周辺のOSSの活発さ(githubから)は圧倒的です。 https://web.cs.ucdavis.edu/~filkov/papers/lang_github.pdf

TypeScript−0.43 TypeScript −1.32 (0.40)∗∗ −2.15 (0.98)∗ −1.34 (0.41)∗∗ −0.34 (0.07)∗∗∗ https://findy-code.io/engineer-lab/github-programming-language-ranking

C言語の特徴_解釈

  • Cコンパイラの普遍性。最大の特徴。CコンパイラはCPUが存在するほぼすべての環境に存在し、存在しなかったとしても作成するのが最も容易です。https://www.quora.com/What-is-the-most-portable-programming-language >Even if there isn't an existing C compiler targeting a particular hardware platform, it is probably the easiest of all languages to create one. https://www.sigbus.info/compilerbook >コンパイラの制作手法を学ぶために何らかの言語を選ばなければいけないとしたら、Cはさほど多くないリーズナブルな選択肢のうちの一つだと思います。
  • トランスパイル容易。C言語は機械語と単純に対応づくことからトランスパイルのターゲットにしやすい。
  • コンピューターに対する完全な制御性。書いたことしか起きないし、何でもできる。ハードウェアに近い開発で良く使われる。カーネルやデバイスドライバは主にCで作成される。フリースタンディング。
  • 高性能。高級言語の中でFortranが最速と言われているが、Cもほぼ同等の性能が出る。
  • アプリ開発では他言語から呼び出される関数の実装で使われる事が多い
  • 脆弱性が多い。しかし静的解析ツールが解決するはず。https://resources.whitesourcesoftware.com/blog-whitesource/is-one-language-more-secure

GraalVM_メモ

最強万能ランタイムまたは巨大な泥団子ランタイム。

  • lliを内蔵している。LLVM IRは中間コードといってもクロスプラットフォーム性を期待できない。https://www.graalvm.org/docs/reference-manual/languages/llvm/ >Note: LLVM bitcode is platform dependent. The program must be compiled to bitcode for the appropriate platform.
  • ネイティブコードの性能が少し落ちるらしい。 https://hackernoon.com/why-the-java-community-should-embrace-graalvm-abd3ea9121b5?gi=11182f32c16b ここのNativeが0.85
  • JVMワールドではなくGraalVMワールドになりそう。例えばGraalVMを前提としたbitcodeを含むライブラリが作られる可能性があるが、通常のJVMで実行できないはず。それはもはやJVM系ライブラリではない。
  • 2019年5月時点でWindows版が無い。
  • Native-Imageでネイティブコードを生成できるらしい。しかし完全対応ではないし、ネイティブ化して配布するならC++とかで作ればいい。
  • polyglot
  • EEの方が性能が良いらしい

WebAssembly_HTML5_解釈

本来アセンブリは移植性が低いものだが、クロスプラットフォームが要求されるwebのアセンブリとは何を意味しているか? WEBブラウザにもともとJS用仮想機械があって、それが中間コードwasmを実行できるようになる。 かつて排除されたJavaアプレットとほとんど同じに思える。

検索するとそれについて述べている記事が見つかった。 https://words.steveklabnik.com/is-webassembly-the-return-of-java-applets-flash JavaアプレットはHTMLやCSS等Web技術と統合的でなかった、と。でもJavaFXはCSS対応している。 さらにJVMとの違いとしてメモリを手動管理できる。よりシビアな性能のため。でもWebページ上でそんな壮大なゲームや科学技術計算をやるか?GC言語の方が開発効率が良いと言われてるから、GC無しで性能を求めるようなプロジェクトは開発効率を犠牲にしてでも性能を求めてるわけで、あまりWeb上でやるものと思えない。

コア開発者にその質問をぶつけた人が居ました。 WebAssembly/design#960 jvmや.netはセキュリティ上の問題があった、と。 でもそれはエンジニアリングの問題のはずで、結局のところやはりJDKや.NETと被るもので、ただ自分達の方が高品質なエンジニアリングができるという事だろう。

WebAssemblyをブラウザ外で使おうという動きもあるようです。WASI

Web_解釈

迷走する巨大エコシステム。 JS、HTML5、WebAssembly、しかもWASIでブラウザ外へ。Webで壮大なゲームや科学技術計算、P2Pまでやる。

WebがOpenJDKや.NET Coreを無視してwasmやwasiで独自のランタイムを作った事は世界的利益のためにソフトウェアプロジェクトが連携できない事を示している。それこそが世界のソフトウェアエコシステムの課題なのでは? 要するにソフトウェアエコシステムに世界的な統合性が無い。

主要ブラウザはC++で作られているが、Javaアプレットの起動はブラウザ自体がJDKベースで作られていたら高速だったろう。 今Wasmが必要とされている事は、最初からブラウザをJDKベースで作りJavaアプレットの高速起動を実現すべきだった事を意味しているのでは?というのも、以下のシナリオが考えられるからだ。
WASIがブラウザ外の仮想機械を作るならブラウザをその仮想機械上で作る事が考えられる。 そして仮想機械を普及させてブラウザと無関係なアプリも含めて全てのアプリをwasmで作ろうとし始める。 そのため豊富なAPIを備えるようになる。 Webのランタイムとしてセキュアなサンドボックス実行をするという特徴は変更され、何でもできるランタイムとなる。 Webページ用途はオマケとなり、WasmAppletと呼ばれるようになり、権限が制限されて実行される。 GCはほとんどの開発でメリットがある偉大な判断の1つだからそのうち搭載される。 JITも折角中間コードがあるなら搭載される。実行時情報を用いた最適化ができる。 そして需要が高い機能が標準APIとして搭載される。 気付いたらWebページ外での実行が主な用途になる。 WebページはWASI仮想環境が提供する豊富なAPIを利用したwasmアプレットを実行し、ブラウザ自体がWASI仮想環境で動作しているので起動処理が無く高速で省メモリ。 つまりJDKと同じものになる

ここまで考えると、アプレットのWebページを実現するにはブラウザ自体を仮想環境で作るべきである事が分かります。ブラウザ全体で省メモリにする、ファイルサイズを抑えるといった事を総合的に考えると、Webページ上で実行されるアプレットと同じ仮想環境でブラウザを作った方が合理的です。もしWebブラウザがJavaで作られていたらJavaアプレットは起動が高速で省メモリだった、という事です。 もし本当にWebがそこに到達したら、Javaアプレットを排除した判断は間違いでブラウザがJDKベースで作られるべきだった事を自ら証明します。 そうじゃないというならwasmやWASIのターゲットは何か?どこでこのシナリオから外れる?

最も活発なエコシステムを持つJSからスタートして注目される、Webという最大のエコシステムで採用されて注目される、ブラウザ外へ進出する、GCを持たせずメモリを手動管理する言語をサポートする事で優れたベンチマークが多数発表される、高性能というイメージを持たせる事に成功したらGCオプションを実装する、人々はほとんどのアプリを開発効率を理由にGC言語で書く、成熟してみればJDKや.NET Coreと変わらなかった事に気付くがその頃にはそれらは死んでいる。うまくバズっている面があるのではと思います。

WebAssemblyやWASIは新しい発明や思想がないように見える。最終的にJDKの同等品に行き着くように思う。

実行時依存性解決_案

JDKが実装するのが良いだろうと思います。

Googleのような圧倒的なインフラを持っているところが、Maven Centralやjcenterのミラーを世界中のエンドユーザーに提供し、エンドユーザー環境でローカルリポジトリを構築する。そしてアプリケーションはpom.xml等に依存関係を記述し、pom.xmlをjarに同梱し、実行時にエンドユーザー環境で依存解決する。なお現状Maven Central等にエンドユーザーがアクセスする事はサーバへの虐待で、実行時依存性解決を実現するには桁違いのインフラが必要です。 エンドユーザー環境でローカルリポジトリが構築されると、他アプリによってDLされたライブラリを再DLする必要がありません。

従来、アプリケーションは他のアプリケーションと同じライブラリを同梱している可能性がありました。しかし実行時依存性解決ではライブラリを重複して配布する事が激減します。ローカルリポジトリは各バージョンのライブラリを持つので正しく依存関係が解決されます。ローカルリポジトリは徐々に肥大化していくので、使っていないライブラリについて定期的に削除する処理が必要です。現時点でmavenはローカルリポジトリに対してそのような処理を行うようになっていません。
実行時依存性解決ならアプリをいくつインストールしてもライブラリはファイルシステム上で共通です。ライブラリの重複した配布が無くなるので、プログラム全体のファイルサイズは小さくなります。ファイルのキャッシュが効く場面が増えるし、近年ストレージの変化はHDDからSSD、さらにNVMe SSDやoptaneなど、ストレージ容量が小さくなる傾向があります。
semantic versioningあるいはそれに準じるバージョニングルールが守られれば、脆弱性があっても自動的に依存関係をバージョンアップして解決できます。エコシステムにおけるバージョニングルールの遵守は最大の課題です。
プログラマーからすればライブラリのマイナーアップデートのためにアプリをアップデートする必要が無くなります。エンドユーザー環境で起動のたびにその時点の最新のライブラリを自動的に使用できるからです。このアイデアは世界で実行されるソフトウェアの品質を飛躍的に高める可能性があります。一方で、主要ライブラリに後方互換性の問題が生じると、多くのアプリが一斉に動作不可能になります。非クリティカルなソフトウェアに向いた仕組みだと言えます。

このアイデアをライブラリだけでなくJDKやそのモジュールに広げる事も可能そうです。各ライブラリやアプリが依存しているjdkバージョン及びモジュールをpom.xmlのようなもので明示し、実行時依存性解決において自動的に必要なモジュールがインストールされ、それで起動されるというアイデアです。

この構想はOS側JDKを前提としていて、リモートリポジトリにアクセスできる環境でなければ成立しません。 しかしこの構想が成立する場合、Java9+のJigsawを不要になります。

私はこのシステムをTenyutalkというソフトウェアで実装するかもしれません。

Jigsaw_解釈

自己完結型はJDKのバグを残す可能性が高い。 世界にばらまかれた自己完結型アプリはいずれ更新されなくなり、JDKの良く知られた脆弱性を残したままになる。 非自己完結型なら、OS側JDKを更新するだけで全てのアプリがJDKのバグを修正できます。 自己完結型はアプリのバイナリ互換性を失わせる。バイナリ互換は仮想機械の利点です。 多くの場合、自己完結型を作るならそのプロジェクトはC++を使うべきです。

世界的なソースコード検索システム_案

githubやMavenセントラル等ソフトウェアを管理しているところが提供する。 IDEはメソッドの呼び出し元を検索する等できるが、 そのような機能をオンラインで膨大なソフトウェアに跨って提供する。 クラスの世界的な利用状況をモニタリングできる。 世界の状況に対応したエンジニアリング、膨大な実装サンプルの検索。

私が空想する少し未来の理想的なプログラミング環境_案

  • OS側JDK
  • OSコール系APIを強化しfat java案やJNI用実行時コンパイル案を採用しバーチャルプラットフォームを追求したJDK
  • 実行時依存性解決をサポートしてライブラリのためにアプリをアップデートする必要を無くす
  • 完全にバーチャルプラットフォームな豊富なライブラリ
  • 仮想デスクトップ機能によるreproducible buildsをサポートしたgithub

Lombokの使用範囲_考察_解釈

EqualsAndHashCodeアノテーションのみ使用する意味がありそうです。メンバー変数を修正した時にequalsとhashcodeの再作成をし忘れると根深いバグを作るからです。ボイラープレートの排除が目的ではありません。コンストラクタやアクセサはコンパイルエラーで気付きそうです。
しかし、Lombokを使用する事自体が問題を起こすかもしれないので、私は結局Lombokの使用に懐疑的です。

プログラミングの本質的進歩とは_解釈

言語仕様、開発ツール等が以下のように改善すること。

  • 最も困難な開発においてプログラマーを助ける。
  • 不可解なバグを減らす。
  • プログラマーを騙さない。
  • 間違いが起きたとして、影響が軽微またはすぐに気付く。

汎用プログラミング言語でビルド処理を書く_メモ

普通ビルド処理はant等で書かれます。私は昔からそれが疑問でした。それで私はJavaでビルド処理を書いた事がありますが簡単でした。commons-ioが便利です。 最近Gradleというものもでてきて複雑なビルド処理ができるようです。しかし私はやはりGradleの必要性が分かりません。 ビルド処理を統一的に記述したいから?統一的に記述すると可読性が高まりますが、Gradleの言語を強制されてしまいます。アプリと同じ言語を使えた方が可読性が高いです。

antやgradleの必要性は分かりませんが、mavenのpom.xmlの「プロジェクトのメタデータを宣言的に記述する」というアイデアは優れています。 そのアイデアは1プロジェクトのビルド処理の範疇を超えて、世界的なプロジェクトの整理や連携に影響します。 もしpom.xmlの情報やmavenの機能をプログラムから使用したい場合maven aetherというライブラリがあります。 私の意見は、pom.xml + java + commons-io + maven aetherでビルド処理を書くというものです。 それが最も妥当な判断のように思います。

プログラミング言語によるビルド処理が必要になった場面_経験

ビルド直前にフォルダやファイルのコピーをしたい事は良くあります。 あるプロジェクトでsrcフォルダにシンボリックリンクを使っていましたが、 OracleJDKから他のJDKへの移行でシンボリックリンクの扱いが変わったようでビルドに失敗するようになりました。 試した範囲ではcorrettoとlibericaはsrcフォルダ中のシンボリックリンクに対応していませんでした。 それで結局Javaでビルド処理プログラムを作成して必要時にフォルダごとコピーするような方法で解決しました。

シンボリックリンクが解決してくれるのはフォルダやファイルに関係する問題だけであり、 あらゆる複雑なビルド処理を想定した場合、Javaでビルド処理を書けた方が対応力が高いです。

あとシンボリックリンクは1つ面倒な事がありました。
a/b/c.txt
a/b/d/
a/e/
フォルダa配下のファイルのうち大部分は別フォルダと同じものを使いたいがc.txtだけ自前のを使いたいとなった場合。 a,bをシンボリックリンクにすることはできません。 d,eフォルダをシンボリックリンクにする事はできます。 もし「c.txtだけ自前のを使いたい」という事情が無ければaをシンボリックリンクにするだけで全て解決します。 つまりただその1ファイルの事情が生じただけで細かくシンボリックリンクを作成する必要が生じます。 そのような細かい管理が生じるので、プログラミング言語でフォルダコピー等のビルド処理を書いた方が楽な方法が見つかります。

P2P_PKI_メモ

※この項目はTenyuについて考える中で私の中に長い間存在していたいくつかの疑問に対する答えです。たぶん意味不明と思います。

ここでP2P PKIと言っているものはTenyu基盤ソフトウェアです。

  • 従来のPKI概念ではなく独自のPKI類似システムを作る理由は何か?
  • P2P PKIは外部システムに認証機能を提供すべきか?
  • P2P PKIの守備範囲を明確化できるか?それはあらゆる観点から評価して合理的妥結か?

従来のPKIはどの現実の組織と通信しているかを確認するという観点に立っていたと思います。 私はP2P PKIについて考えました。それは現実の組織を認証するためではなく、 ネット上の主体を認証するためにあり、P2P PKIにおける信用はネット上の活動を通じて創造され、現実の組織の信用を流用しません

P2P PKIはネットユーザーの信用の数値化や現在のIPアドレスやP2Pネットワークで共有されたファイルやDB等を外部アプリに提供できます。 P2P PKIはサーバーモードを設定できて、エンドユーザー環境とサーバー環境両方をサポートします。 そしてインターネットを新たな信用を創出する場にする。それはそこに新たな経済を創出しうるという事です。

OOPとは_説明_解釈

オブジェクト指向という言葉は大まかに分けて3種類の意味があります。

  • アランケイのオブジェクト指向。 https://ubiteku.oinker.me/2016/05/09/what-is-oo-all-about/ >ケイ氏は、オブジェクトを、ネットワークを形成してメッセージを送り合うコンピュータのメタファーとして捉えており、インターネット上のサーバーのように、リクエストをメッセージとして受け取り、そのメッセージをサーバー側で解釈して何らかの処理を行うというモデルを想定していた。

    一見するとこの意味のオブジェクトはカーネルが実現しているプロセスという概念に一致するように思えます。基本的にメッセージングはプロセス間で行われます。しかしオブジェクトレベルのメッセージングも実現されています。RMIがそうです。 ダイナブックやSmalltalkを見ると、アランケイはユーザー中心のコンピューティングという思想を展開していて、そのイメージはプログラミング言語だけでなくOSか仮想環境を含んだものだったと思います。 アランケイのオブジェクトはRMIに標準的に対応したプログラミング環境におけるオブジェクトだったろうと思います。

    私はその観点を進めてTenyutalkに書きました。

  • JavaやC++で用いられるオブジェクト指向。 実はこの意味のOOPは構造化プログラミングですそしてアランケイのOOPはC++等に何ももたらしていません。 共同詳細化がinterfaceにまつわる概念で、抽象データがabstract class、抽象化文がそのメソッドです。 https://ja.wikipedia.org/wiki/%E6%A7%8B%E9%80%A0%E5%8C%96%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0 >抽象データとその上で動作する抽象化文の共同詳細化

    なおこの観点はwikipediaで活動していたMonadaisukiの投稿から影響を受けたものです。

    https://www.cs.utexas.edu/users/EWD/transcriptions/EWD02xx/EWD268.html これをJava的に解釈してみる。 refinementはソフトウェアの洗練、つまりリファクタリング。

    「抽象クラス等を用いたプログラム(abstract program)の改良において、「連動的リファクタリング」現象を観察した。一部の振る舞いを抜き出した(a given type a certain representation is chosen)1つのinterface型(in terms of new data structures)を実装した複数の抽象クラスにおいて(For abstract data structures of)。その設計判断が少なくとも意味する事は(The immediate consequence of this design decision is)その複数の抽象クラスのメソッド(the abstract statements operating upon the original abstract data structure)は実装するinterfaceを必ず追従して更新されなければならない(have to be redefined in terms of algorithmic refinements operating upon the new data structures in terms of which it was decided to represent the original abstract data structure)。interfaceはソースコード上で独立した単位であるべき(Such a joint refinement of data structure and associated statements should be an isolated unit of the program text:)。そしてinterfaceはその実装クラス群が追従して更新されるという設計判断と(it embodies the immediate consequences of an (independent) design decision and)、プログラムの修正の中で自然に交換可能な単位を記述する(as such the natural unit of interchange for program modification)。これは、私が「真珠」と呼ぶようになったものの一例です(It is an example of what I have grown into calling "a pearl")。」

    C++にも純粋仮想クラスというinterfaceのような概念があったが、 isolated unit of the program textという一文はそれを独立した概念として扱うべきことを指摘しており、 それはJavaのinterfaceのような概念である。 pearlはカプセル化された振る舞いの単位。そのような単位の実装において他のそのような単位に依存している、つまりあるクラスの定義の中でinterfaceが使用されていて、実行時には何らかのそのinterfaceの実装が選択されているが、その実装の実装でもやはりinterfaceが使用されていて、そのinterface実装interface実装という繰り返しは低水準なところまで続いている、これがneckless。1つpearlの内部に入り込むたびに1つ抽象度が低下し、最後にはマシンレベルに到達する。

    「interfaceの実装クラス群は何らかの設計上の選択肢を意味するので(As each pearl embodies a specific design decision)、interfaceの実装クラス群はプログラムの修正の中で自然な交換可能単位であり(it is the natural unit of interchange in program modification)、あるいはそれは場合によって要件の変化への適応である。 (or, as the case may be, program adaptation to a change in problem statement)」

    そしてエドガーダイクストラはpearlのハードウェア実装について語り始める。実際それはJDKというある種の仮想環境でハードウェアではないが実現された。ハードウェア実装は固定長である必要がありPearlが内部に持つデータはたびたび可変長になると思われるので実際のハードウェアによる実装は無理で仮想機械による実装になる。

    「interface振る舞いを実装したクラスとそれによる実装の選択可能性は(Pearls and necklace)抽象的な部分が残され実装を選択しきっていないプログラムへ実装の選択というある種の設定値を与える作業である(give a clear status to an "incomplete program")、不完全な実装とはそのinterfaceと実装の繰り返しの下部実装を排除した場合の上部実装である。(consisting of the top half of a necklace;)。下部実装はコンピューターで実装可能であり上部実装はそのプログラムとみなせます(it can be regarded as a complete program to be executed by a suitable machine (of which the bottom half of the necklace gives a feasible implementation))このとき上部実装は下部実装に拠らず意味的に確立している(As such, the correctness of the upper half of the necklace can be established regardless of the choice of the bottom half)。」

    エドガーダイクストラはその上部実装を、下部実装を実装したコンピューターの"マニュアル"と表現した。マニュアルは機械の操作手順のようなニュアンスだろう。マニュアルという表現が与える印象は、その下部実装コンピューターは汎用コンピューターというニュアンスから離れてそれを操作する事がマニュアルと表現されうるような特定目的の汎用性が限定された機械の操作手順ということ。 そして完全にJavaのinterfaceに相当する概念に言及している。

    「上部実装と下部実装の間を切断できます(Between two successive pearls we can make a "cut",)。上部実装は下部実装が提供する機械の操作手順です(which is a manual for a machine provided by the part of the necklace below the cut and used by the program represented by the part of the necklace above the cut.)。その操作手順は上部実装と下部実装の間の規格を意味します(This manual serves as an interface between the two parts of the necklace.)。我々はそれを上部と下部の間の規格(data representation as an interface between operations)として捉えるよりも要件の変化に適応するためのプログラムの修正における実装の交換性を確保する(ensuring the combinatorial freedom required for program adaptation)ために役立つと考えます。」

    data representationはオブジェクトの振る舞いobject behaviorというニュアンスだろう。一時の場面に着目すれば下部実装が上部実装に対して見せるものはオブジェクトの振る舞いだが、より長期的に捉えれば実はそれは下部実装の交換可能性である、と。
    規格というと機械の連携のためというニュアンスで、それは例えばABIなども含まれ広く連携のための概念だが、要件の変化に耐えるための実装の交換性という捉え方はソフトウェアプロジェクトの一生がイメージされている。
    エドガーダイクストラは1つのソースコード上で各interfaceの実装クラスを選択した時のその実装クラス群を家族familyと呼んでいるようだ。注意点として家族は同じインターフェースの実装クラス群ではない。1つのソースコード上の全interfaceにおける実装クラスの選択の結果が家族である。つまりDIフレームワークが提供する一括的な実装の選択、その結果がfamily。

    「interfaceによる実装の交換可能性はプログラムが潜在的に様々なバージョンを実現する唯一の方法です(The combinatorial freedom just mentioned seems to be the only way in which we can make a program as part of a family or "in many (potential) versions" without the labour involved increasing proportional to the number of members of the family)。(The family becomes the set of those selections from a given collection of pearls that can be strung into a fitting necklace.)。」

    エドガーダイクストラは今日のDIフレームワークのようなinterfaceを作りまくり実装を任意に選択できるプログラミングを構想していた。Neckless言語

    Simulaは構造化プログラミングに分類されていますが、既にクラスを扱っていました。 https://ja.wikipedia.org/wiki/Simula >クラス(class)の構文と対象(object、オブジェクト)の概念を初めて導入した言語である 今日のOOPに影響を与えたのはダイクストラの構造化プログラミングです。 https://ja.wikipedia.org/wiki/%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E6%8C%87%E5%90%91%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0#%E6%AD%B4%E5%8F%B2 >部品化を推進する仕組みが提唱され構造化プログラミング (structured programming) として1967年[要出典]にエドガー・ダイクストラ (Edsger Wybe Dijkstra) らによってまとめあげられた

  • プロトタイプベース
    これは構造化プログラミングともアランケイのOOPとも全く違います。 https://www.ibm.com/developerworks/jp/web/library/wa-protoop/index.html

ということで、Java等のOOPをStructured Programmingと言い換えるべきです。 でもSPと言っても通じないから難しい。 OOPという言葉で指定される意味にはユーザー中心コンピューティング、SP、プロトタイプがあります。

継承より構成_比較_考察

構成=compositionとして使っています。 結論から言うと、継承とユーザーコードによる構成はどちらも問題がありました。 構成で継承を代替しようとするとユーザーコードによる相互参照が生じる。 あと構成は多態性をうまく実現する方法もない。 継承は子孫クラスが絶対に備えるべき状態を記述できるが概念設計の変化によって継承構造全体が崩れうる。 それで新たな言語仕様について他の項目に記述しましたが、ここでは継承も構成もダメだという事について書きます。

継承への注意喚起が行われた事は正しい。 プログラムが保守困難になる原因の一部は継承です。

継承は親子クラス間の相互依存を言語仕様でサポートしていて、親クラスから子クラスは仮想メソッドによって抽象化されている。それを構成に置き換えた場合、その相互依存をユーザーコードによって記述する事になる。そして仮想メソッドが無いのでより密結合になる。あるいはinterfaceを大量作成するようなコードになる。

継承を構成で書き換えると相互参照が生じる事について説明します。 なお相互参照は循環参照とも呼ばれアンチパターンの1つです。 https://en.wikipedia.org/wiki/Circular_dependency https://en.wikipedia.org/wiki/Acyclic_dependencies_principle

こういう3階層の継承があったとします。
Parent2>Parent1>Child
abstract class Paren2{}
abstract class Parent1 extends Parent2{}
class Child extends Parent1{}

これを構成で書くとこうなります。
class Paren2{}
class Parent1{}
class Child {
private Parent1 p1;
private Parent2 p2;
}

継承では子クラスは親クラスに依存できます。つまりChildやParent1はParent2のpublicまたはprotectedな要素にアクセスできたはずです。 親クラスは仮想メソッドを通じて子クラスで振る舞いを変更できますこのような継承における上下の依存関係を構成で再現するにはこうなると思います。 interfaceを乱立させるような別の書き方もありそうですが、interfaceの乱立自体が問題になります。
interface EverythingHolder{//child,parent1,parent2の全組み合わせに対してinterfaceを作るべきかも
Parent1 getParetn1();
Parent2 getParent2();
Child getChild();
}
class Child implements EverythingHolder{
private Parent1 p1;
public void do(){
p1.method1(this);
}
}
class Parent1{
public void method1(EverythingHolder host){}
}
p1やp2のメソッドを呼び出すときいちいちthisを与えます。するとp1やp2はthisを通じて全オブジェクトにアクセスできるので、継承にあった親子クラスの相互依存を再現できます。 メソッドでthisをいちいち与えるのが面倒だからとParent1やParent2のメンバー変数にChildを持たせるかもしれません。 それは継承よりも強い依存です。継承では親クラスから子クラスを参照する事はできず、そのタイプの依存性は仮想メソッドで抽象化されます。

ここまでの苦労を払って、構成は何をもたらすか? 実行時のp1,p2の変更もありますが、最も重要なのは継承構造全体が破綻するような概念設計の変化への対応です。

継承の長所について。 継承は意味を記述できている。一般にクラスは様々なメンバー変数を持ちますが、親クラスを継承する記述は他のメンバー変数のクラスとの意味的な違いを記述します。 class A extends B{
private C c;
}
BとCではAとの関係性が違うという事です。具体的にはcはセッター等で置き換わるかもしれませんが、Bのインスタンスが置き換わる事はありません。 ところが構成ベースで作った場合、親クラスはメンバー変数の1つになります。その意味的な違いの記述を失っており、可読性の低下です。

継承や共通化という語に関する意見を見ているとほとんどヘイトと言っていい印象を受けます。 継承とか共通化は悪だ、クソだ、と。代わりに構成や抽象化を考えろと。 しかしその理由を追ってみると説得力がない。藁人形論法のようです。 継承の本当の最悪な問題は概念設計の変化による継承構造全体の崩壊です。 これをたびたび起こすから継承は憎まれます。 私は、コードの冗長性をトリガーとして共通化を考えるという方法論は有効だと思います。 抽象クラスにせよ構成にせよコードの共通化はほとんどの場合伴います。 どう共通化するかが問題なだけです。

もう1つ良く言われる事として「抽象クラスとは振る舞いだ」という意見があります。 しかしinterfaceも振る舞いを記述します。 interfaceと抽象クラスの違いを意識したうえで抽象クラスの特徴は何かというならその説明は不十分です。 実際、抽象クラスは状態の共通化から作成する事がほとんどだと思います。

既に書いた通り、構成で継承を代替すると循環参照が生じます。ホストオブジェクトや多数の委譲先オブジェクトが相互依存できるよう記述する必要があるからです。しかもそれがユーザーコード上で生じます。 私は、継承が問題を起こしやすい事を理解できますが、構成が解決策だと思えません。

もし全子孫クラスが絶対に持つべき状態があるならそれは継承で与えるべきです。 例えば、継承なら抽象クラスにidフィールドを置いて全子孫クラスに継承させれますが、 構成的に記述されたメンバーオブジェクトがidフィールドを持つというやり方だと、そのメンバーオブジェクトがクラスによってtransientになっているかもしれません。そうすると、通信や永続化される場合にidがある事が保証されません。 class Parent{ private Long id; } class Child extends Parent{} class Composition{ transient private Long id; } 他には、interfaceだと状態として持たずにオンラインアクセスで取得して返すような実装になっているかもしれません。

とはいえ私は常に構成を使うべきだという人達の意見も分かります。しかし相互参照の記述が嫌です。 継承は密接な相互依存関係をユーザーコードではなく言語仕様の上で扱えるという点で優れていると思います。 他にも継承は本番用クラスを継承してテストクラスを作るとか、非常に便利な場合があります。

特に問題になるのはモデル設計における継承です。 継承も(ユーザーコードの)構成もダメです。 密な相互依存をうまく扱える親子関係じゃない言語概念が必要です

構成的多重継承_素案

継承より構成_比較_考察の解決策。

多重継承される事が可能なcompositionalクラスという言語仕様を作る。 構成的多重継承はcompositionalクラスを多重継承する。
ClassA extends CompositionalClass1, CompositionalClass2
compositionalクラスのメソッドは再帰的に呼び出される。
ClassA#equalsが呼び出されたら
CompositionalClass1#equals
CompositionalClass2#equals
も呼び出される。
多重継承の典型的問題としてひし形継承の問題が良く言われるが、この再帰的呼び出しによって解決される。 compositionalクラスは直接newされず、子クラスを通してnewされる。

構成的多重継承は意味的にis-a関係じゃなくなる。 has-aで多態性を持ちうる。

実際のところcompositionalクラスは何らかの性質を表現するだろう。

メソッドの引数の型に複数のcompositionalクラスを指定できたほうがいいだろう。 func(CompositionalClass1 CompositionalClass2 arg1);

構成的多重継承は継承が抱える全ての問題を解決しないかもしれない。 compositionalクラス間の依存ができないから。 class NormalClassA extends CompositionalClass1, CompositionalClass2
ここでCompositionalClass1とCompositionalClass2は互いに依存できない。 この点で従来継承で解決されていた問題の一部が構成的多重継承では解決できないという事になるし、compositionalクラスで表現されるべき概念は根本的性質のようなものであるべきで他の性質との相互依存は子クラスで解決されなければならない。

多重継承された各compositionalクラスは相互依存できます。
仮想メソッドで横の関係にあるcompositionalクラスの情報を取得できる。
//in CompositionalClass1
abstract CompositionalClass2 getCompositionalClass2();
このメソッドを子クラスに実装させる。子クラスはCompositionalClass2を継承しているのでthisを返すだけ。
するとCompositionalClass1からCompositionalClass2を参照できる。

構成を言語仕様でサポートする_parent_素案

この案は構成的多重継承_素案とかなり類似している。

compositionalクラスという概念を作り、そのインスタンスは 「メンバー変数としての参照が1か所からに限定され、常にいずれかのオブジェクトのメンバー変数として参照されていて、その制約によって常にただ一つの親オブジェクトが存在する事が保証される」というアイデアで、構成の要素側(compositionalクラスのインスタンス)からホスト側(親オブジェクト)へのアクセスを可能にする。

発想の経緯

compositionalクラスのメソッドから親オブジェクトを参照できる。
public compositional class Member{
public void func(){
parent.someMethod();//thisみたいな感じでparentが使える。
}
}
public class HolderImpl implements Holder{
private Member m1 = new Member<>();//m1と同じインスタンスへの参照はここにしかない。
}
Holderインターフェースはその構成内で相互参照を実現するための、その構成内の標準知識のようなもので、そこに各メンバーへのゲッターを備えれば構成内で相互参照ができます。

さらにcompositionalクラスのインスタンスをメンバーに持つ場合、継承と同様に自動的にそのインターフェースを持つとしても良いと思います。つまりHolderImpl#func()が自動的に存在するという事です。HolderImplがMember m1を持つからm1のメソッドが透過的に見えるという事です。 このルールによって多態性が実現されます。 Memberを期待するメソッドにHolderImplオブジェクトを渡せます。

さらに、あるクラスの全てのcompositionalクラスに特定のインターフェースの実装を強制できるといいかと思った。 例えばHolderImplがそのメンバー変数のうちcompositionalクラスであるものについてvalidate()インターフェースの実装を要求する。 そしてcompositionsというキーワードをthisやparentのように使えて、そのクラス内のcompositionalクラスである全メンバー変数を参照できる。
//in HolderImpl
for(CompositionalMember e : compositions)
e.validate();
このようなコードが可能になるように。

このアイデアは構成的多重継承_素案と類似した事を言っているだけですが、多態性と横の関係(多重継承やメンバー変数)を維持しつつ相互依存(親オブジェクトparentやcompositionsや子クラス制約等)をサポートするというのが根本的アイデアです。それをうまく達成できれば何でもいい。

この案はクラスのバージョンアップに強い。 シリアライズされたオブジェクトのクラスのメンバー変数の定義が変わるとデシリアライズできなくなるが、 古いクラス定義を残しつつ新しいクラス定義を用意してDBからの読み取り箇所でオブジェクトをバージョンアップする事が考えられる。 その時抽象クラスの変更は全子孫クラスに影響する(内容が同じ新たなクラス定義を用意する必要がある)が、 メンバー変数の変更なら末端の子クラス1つだけ新しいクラス定義を用意すればいい。 その点でこちらの方が本筋かもしれない。

Neckless言語_解釈_説明

エドガーダイクストラが言及していたNeckless概念が大体わかった。 JavaのDIフレームワークを用いたプログラミングがかなり近い。

  • クラスはクラスに依存してはならない。
  • クラスはinterfaceに依存する。
  • interfaceは多数の実装クラスを持ちうる。
  • 一括でシステム全体の実装クラスを選択するような方法を作る。ダイクストラ的familyを作る方法。

このような原則を徹底する事で実装クラスの交換によるソースコードの状況適応力を最大化する。

しかし私はGlbやcompositionのような方向性が有望だと思う。

私の中でinterfaceとは何か。 約束または規格であり、変更困難な、将来に渡って保証されるシステム上の前提の一種である。そのような概念を見出す事も変更する事も非常に重い。 例えば抽象的な確固たる概念を述べるinterfaceがある。JavaにList,Map,Set,Collection,Iterable等のinterfaceが定義されている。これらが変更されたらほとんどのJavaプログラムは動作しなくなる。 あるいはプラグイン機構を実現するための外部インターフェースがある。もしそれが変更されたら全プラグインを修正する必要がある。 ライブラリが他プロジェクトに公開する振る舞いもしばしばinterfaceとして定義されるが、もし変更されたらそのライブラリを使用している多数のプロジェクトに影響する。

リリース番号_案

tenyuで用いているリリース番号という概念は、 リリースのたびにそれに依存したデータやソフトウェアが世界のどこかで作られていく、というイメージに基づいている。 公開しない限りどれほど大幅な変更が行われても問題にならない。 ”リリース”が意識すべき区切りとなり、ソフトウェアエコシステムに配慮すべき単位を作る。

ソースコード公開確認API_案

githubやbitbucketは登録されたプログラムの全リリースバイナリについてそのハッシュ値を記録する。 そして入力されたハッシュ値が登録済みか、つまりソースコードが公開されているかを判定できるようなapiを提供する。

セーフランチャー_案

ソースコード公開確認や作者信用数値を確認するランチャー。 ランチャーソフトウェアで起動直前にソースコードが公開されているかチェックする。 ソフトウェアのセキュリティに寄与する可能性がある。

3Dゲームにおける演出用サブ物理空間_案

髪の毛やスカートなどひらひらしたものは物理演算した方が開発効率や見栄えにおいて優位性がある。 しかし主にボーンアニメーションで行われているようだ。 物理演算は重いので慎重に使わないとゲームに適さないが、髪の毛やスカートに限定するなら広範囲の相互作用を無視してもいいので、うまく並列処理できるはず。髪の毛やスカートのひらひらは純粋に演出的でありゲームロジックや対戦における有利不利に影響しないので、1キャラクター内での純粋に演出的な物理演算という事で処理できる。 現在CPUはRyzenによってコア数が急増しつつあるので状況に適している。 技術的イメージは演出用サブ物理空間を作り1キャラクター限定で演算し、全オブジェクトの相互作用を扱うゲームロジック用のベース物理空間と分ける。 演出用サブ物理空間はキャラクター毎の空間で、その中で髪の毛やスカート等のひらひらを物理演算する。キャラクターの体の動きや装備品の動き等の影響は受けるが、他のキャラクターの影響は受けない。 つまり髪の毛やスカートは他のキャラクター等と衝突しない。自キャラ内での衝突や速度による変化等が影響する。 一方で、ゲームロジック用のベース物理空間では、キャラクターは1個の球体など単純な図形として扱われ、他のキャラクターや物体等との広範囲の衝突判定が行われる。

jme3のDynamicAnimControlのRagDollサンプルコードは各ボーンに物理オブジェクトを設定したりリンクを設定して運動学的モーションを実現している。その動作はかなり面白いが、モデルの形状によってゲーム上の有利不利が生じるので対戦ゲームでは問題がある。特に使用するアバターを自由化しようとするなら対戦ゲームにおいて当たり判定は全キャラクター共通の単純な形状であることが望ましい。

とはいえ衝突部位に応じて変化する運動学的モーションは演出上魅力的なので、対戦上の有利不利のためにあくまでキャラクターはベース物理空間上で単純な球体の衝突範囲を持つべきだが、その球体の衝突箇所がそのキャラクターのサブ物理空間に通知されて演出だけ運動学的になる、キャラクターの速度はベース物理空間で決まる、というのはよさそうだ。このアイデアは性能と演出のバランスが取れている。

オンラインゲームの物理演算_案

このようなアイデアは実証しなければあまり意味が無いが、実証できていない。たぶんそのうちやる。 これはゲームロジック用のベース物理空間の話。 一般にオンラインゲームで物理演算は難しいと言われている。 問題

  • キャラクターが位置補正を受けてワープするのがプレイヤーにとってストレス
  • 僅かな位置の違いで当たったか外れたかが変わり、当たった場合吹っ飛ばされるが吹っ飛ばされる角度も僅かな位置の違いで変わるので、物理演算によって僅かな違いが大きな違いに繋がる。 解決策
  • 各プレイヤーキャラクターは自分の位置と速度を主張し、他のプレイヤーキャラクターが主張する位置と速度を受け入れる。つまり自キャラがワープする事は無い。他キャラ、他オブジェクトはワープする。
  • HPなどは、ノードに序列をつけて上の序列からのメッセージを採用する。ホスト概念がある場合、ホストノードは最上位。
  • 自キャラの位置と速度について他プレイヤーに定期的に送信して同期する。
    • 自キャラの近くにいるプレイヤーには高頻度で同期する。遠くにいるプレイヤーには頻度を低下させる。
    • 定期的な同期の他にイベントベースの同期を併用する。例えば位置や速度の急変があったら全プレイヤーに送信する。
    • 自キャラ及びペット及び自分の投射物の数はせいぜい5程度と思われる。
    • 位置と速度は1オブジェクトにつき40バイト程度で送信できると思われる。
    • 10人対戦を想定し、他のプレイヤーの人数は9人を想定。
    • 1秒あたり60回同期できればラグを感じないと予想。
    • 送信量 5 * 40 * 9 * 60 = 108KB/s 受信量はその9倍で972KB/s ただしこれは多めの見積もりで、実際自オブジェクト数は2以下と思われるのでこの半分以下で済むだろう。受信量で8Mbpsが最も厳しい性能要件になるものの、最近の回線なら問題ないはず。
    • 同期メッセージは連番のIDを持つ。受信側は最後のIDを持ち、それより新しいメッセージのみ反映し、最後のIDを更新する。
    • 同期頻度が高すぎて回線負荷が高まり、せいぜい数十人程度の同時プレイしかできない。しかしインスタンス空間で限られた人数で開催されるゲームなら可能。

このアイデアはクライアント優先の場合があるのでチートが容易になっているが、Tenyuの場合リプレイファイルや紹介制ユーザー登録などがチート対策になるので問題無い。

ソフトウェアプロジェクトの死_問題

人気言語ではライブラリが豊富にあるとよく言われます。 しかし大事な事は生きたプロジェクトがどれだけあるかです。 死んだプロジェクトは検索を妨害するし、プロジェクトの死亡率が高いとライブラリ選定における比較検討を難しくします。

ネットにアクセスするコンピューターの水準を底上げする_問題_解釈

日本のスマホは回線代に端末代が含められている。 そしてユーザーは定期的に端末を無料で最新のものへ交換する。 そのモデルは端末の水準を保つために優れています。

コンピューターはたびたびハードウェアレベルの脆弱性が発見されますが、リコールされません。 コンピューターは性能向上が著しく、数年で買い替える人が多いし、リコールは合理的でない。 定期的に新しいコンピューターに買い替えさせるのが正しい。 それを強制できるビジネスモデルはコンピューターセキュリティにとって有益です。

セキュリティだけでなく、極端に古く低スペックなコンピューターをソフトウェア開発者が想定しなくてよくなる。

PCにおいても水準を保つ工夫が必要です。

創発的なソフトウェア_解釈_案_思想

オープンソースや自由ソフトウェア等FOSSが注目される本質的理由はそれら概念がソフトウェアを世界の共用資産にする事になり、ソフトウェアエコシステムにおいて世界的な創発的現象に繋がるからです。 私はソフトウェアのための世界で1つの共同資本という言葉を使う場合がありますが、FOSSの充実は共同資本の成長の1つです。 FOSSの価値観はソフトウェアの生産性にとって最も理想的です。

オープンソースや自由ソフトウェアは世界の共用資産を目指す性格のソフトウェアです。 TenyuLicenseのソフトウェアもFOSSです

私はソフトウェアやオンラインサービスについて創発的と言う場合があります。 ソフトウェアが創発的であるかは、世界の共用資産である事を目指す性格があるか、ソフトウェアの最大の生産性を目指す性格があるか、創発的現象に寄与するか等が基準になります。 ソースコードが非公開のオンラインサービスでも創発的とみなせる場合があるかもしれません。 つまり、ソースコードを公開したり自由なライセンスにする事は創発的であろうとする一手段に過ぎず、必須の条件ではないという事です。

自由ソフトウェア_コピーレフト_オープンソース_TenyuLicense_比較

オープンソースと自由ソフトウェアは作者の経済的利益の達成方法について十分に説明していない。 Tenyuの構想では、ソフトウェアの自由な相互利用と作者の経済的利益を両立できる。 さらに、誰がどの程度貢献しているかデジタルに記述され、その情報が公開される。

GNUとLinuxとUnix_解釈

GNUはUnixを模倣するために始まりました。 LinuxはMinixを参考にして作られました。 MinixはUnix系OSです。 そのような事実に対して、GNUやLinuxはパクリであると批判する意見を僅かに見た事があります。

Tenyuの構想である作者権やTenyuLicenseは私の創作に対する思想を示したものですが、その観点からすると、僅かでも真似をしたらダメというわけではなく、独自の創作性が十分に入っていて、かつ参考にした他の創作物を明示していればほとんどの場合問題ありません。

GNU,Linux

  • 成果物が無料で公開され世界的な創発的現象を引き起こしました。
  • 社会を騙そうとしていません。何を参考にしたか明示しました。
  • 独創的な創作活動です。

そのようなプロジェクトを否定した場合、100%独自の創作物のみが肯定される事になり、非現実的です。

リベラル_思想

リベラルの本質は世界をより創発的にする事です。 良く寛容さと訳されますが、寛容さは場合によって世界をより創発的にすると思いますが、リベラルとされる行動全般を説明しません。 OSS、途上国の成長を助ける事、子どもの貧困を解決する事、ネットで様々な学習情報が提供されている事などは世界をより創発的にします。 何が世界をより創発的にするかは明白に判断できる場合もありますが、難しい場合もあります。

staticを使うべき場面_経験

私が遭遇したstaticを使うべき場面について。

  • Glbのメンバー変数及びアクセサ
  • interfaceに付随した定数。 interfaceは「仕様を記述している」という意識が強いが、例えば連番のIDで最初のIDが何番か(通例0か1)、特殊な意味を持つIDが何か、-1,-2,-3等が特殊なオブジェクトに設定される場合など、と言った仕様についてinterfaceにstaticに定義している。
  • オブジェクトをDBに登録するための一連のDB操作シーケンス。 複数のストアに一連の操作をするコードはどこに書くか?私の場合、そのような一連の操作の必要性はモデルによって生じていたので、モデルクラスにstaticメソッドとして定義した。DBがグローバル状態の一種であるからこの設計が妥当だと思った。
  • 複数コンストラクタ。 Tenyu基盤ソフトウェアに含められているIDListクラスは膨大な数値配列または数値リストを受け取って、それを圧縮した1オブジェクトにする。 この圧縮アルゴリズムは優秀でデータにもよるが10~20分の1まで圧縮できる。 しかしintの範囲に限られていてlongに対応していないので、 long範囲を扱う工夫としてstaticメソッドとしてListを返すメソッドを定義した。 「そのクラスのオブジェクトを多数コンストラクトするメソッド」はコンストラクタにできないし、 staticメソッドにしておくのが一番まとまりが良い。

NVMe_SSD_予想

NVMeを使ってもゲームのロードが高速化しないという話がありますが、恐らくCPUのコア数が不足しているか、ゲームがアセットを並列にロードしていません。 アセットは大抵の場合圧縮されていたり、ゲームエンジンにとってネイティブではない形式で保存されているので、変換処理が必要になり、アセットを読み込む時にCPU負荷が生じます。 今後CPUのコア数が増えると思うのでNVMeはゲームでも有力なはずです。

デシリアライズ用コンストラクタ_案

Kryoなどシリアライザはコンストラクタを呼び出さないとフィールドを初期化できない。 そのせいで、初期化処理が走った後に再度メンバー変数に値が設定されていて二度手間になっている面がある。 デシリアライズ用のコンストラクタを暗黙的に備えて、一部の初期化処理をシリアライザに委譲すれば解決するはず。

OSがLLVM標準搭載_案

OSがLLVMを標準搭載するとLLVM IRを実行できるので、プログラムをLLVM IRで配布する事を標準化できる。 IRは特定の命令セットに依存している場合があるが、依存していない場合もある。 OSがIRプログラム起動時にIRから機械語へのコンパイルをLLVMによって行い、それを実行する。コンパイル結果をキャッシュする。 こうするとLLVMが新しいCPUに対応すれば既存のプログラムが同時に対応完了する。 ただし特定の命令セットに依存しているIRはそうではない。

CPU命令セットの爆発的多様化によるセキュリティの改善_予想

任意の機械語を実行可能な脆弱性がどこかで発生し、攻撃者が任意の機械語ウイルスを実行させるとして、もしCPU命令セットが多様化していると正しい命令セットを特定できずに失敗する。 あり得る全ての命令セットについて網羅的に実行していったら?無意味な機械語ウイルスを実行した結果としてプロセスが終了する。 実行中のプログラムに、その脆弱性を突いて任意のコードを実行させる場合、基本的には何らかの機械語を流し込む事になる。システムによってはSQLや中間コードを流し込む場合もありうるが。 だからCPU命令セットの多様化は潜在的にセキュリティを改善する。

OSは多様化するか_予想

OSはデバドラの移植が難しい事によって守られているので無理だろう。 しかしLinuxディストリの多様化や既存OS間での移行、マルチブート環境が広がる事はありうる。 Fuchsia等新しいOSも開発されているが、今のところ流行る気配はない。 新しいOSが使用されるとしたら周辺機器を決め打ちできるスマホ等で、多様な周辺機器を扱うデスクトップPC用途では難しいだろう。

LLVMとJDK_考察_案_メモ

LLVM IR

  • CPU命令セット及びOSの間で移植性がある実行バイナリを作れる。
  • リフレクションや動的なクラスのロードをサポートする。

AzulのfalconはLLVMによるJITでc2を置き換えたようだ。そしてc2より高性能化したと。
追記:RoboVMもLLVMベースのJDKだったようだ。

JDKはLLVMの最適化技術をどう取り込むか? OSがLLVMを標準搭載し、JDKのJITがbytecodeからLLVM IRを作り、OSがLLVM IRを機械語にして実行する。 JDKの開発者はCPUアーキテクチャや一部の最適化について悩む必要が無くなる。

SharkというプロジェクトがLLVMによるJITを実現しているようだ。 しかしZeroというマイナー環境向けにOpenJDKを作りやすくするためのプロジェクトにおいて使用するマイナーなものという位置づけでしか捉えられて無さそう。 https://icedtea.classpath.org/wiki/ZeroSharkFaq

プログラムの統一_プログラマーの均質化_案

同じ言語で同じ意味のプログラムを書く場合でも人によって書き方が変わる。 性能やセキュリティの違いがあってやっているなら良いが、無駄な多様化の場合もある。 できるだけ無駄な多様化を防ぎ、共通化する事がそのエコシステムの価値を高める。

  1. 公式wikiで各領域のサードパーティライブラリをまとめる。その言語のニュースサイトも提供する。
  2. 長期deprecatedという概念を作り、20年後くらいにその仕様を廃止する。徐々に世界のソースコードが最新の記述方法に統一されていくよう仕向ける。
  3. サンプルアプリの実装例を公開し、プログラマーに読ませる。

JVMが実行時にアプリを切り替える_案

AoTコンパイルはクラウドに適切なNativeImageを作成するが、もっといいアイデアがある。 疑似カーネルと言っているアイデアを使う。 つまりJVMが実行時にアプリケーションを切り替える。 クラウドのノードにおいて、予めJVMプロセスが起動されていて、その後にアプリを選択し、さらに随時切り替える。 このときクラスローダーの状態を引き継ぐ。 複数のアプリが同じライブラリを使用し、しかしライブラリのバージョンが違う可能性がある。Module代替案参照。 もし偶然直前に実行されていたアプリと同じライブラリ同じバージョンに依存していた場合、クラスロードが不要になる。 rt.jar等の基本的なクラス群は再ロードを省略できる。 JITは実行時の状況に応じて最適化するから、実行するアプリケーションの変化に対応できるはず。 このアイデアはクラウドだけでなくPCにおいても適用しうる。

このアイデアはネイティブコンパイル型を出し抜く高速起動を実現しうる。 一方でプロセスに与えられた権限に関する新たな脆弱性を作りうるので、その問題をまとめきれないならこのアイデアは成立しない。

Moduleと疑似カーネル案_案

動的な公開範囲の設定を達成できるならModuleは有用。 OSGiがこれを達成しているらしいがJava標準のModuleシステムが代替するかもしれないから調べていない。

少なくとも日本語圏ではmoduleはjar hellを解決すると紹介されていることが多いが、依存性の記述においてバージョンを指定しないのでjar hellを解決できる可能性は無い。 例えばこの記事がそれについて言及している。 https://blog.codefx.org/java/dev/will-there-be-module-hell/

しかしModuleは依存性解決を対象としていないらしい。 https://softwareengineering.stackexchange.com/questions/358396/how-does-java-9-manage-module-versions http://openjdk.java.net/projects/jigsaw/goals-reqs/03#versioning

よく考えてみると確かにModuleでバージョンを指定する必要性はない。 Moduleシステムの強みは何か? パッケージが全公開から一部公開になるということで利便性が低下するようにも思えるが、例えば異なる作者による多数のアプレットを動的に読み込むようなアプリを作る場合、ホストアプリがアプレットにどのパッケージを公開するか制限できないとセキュリティが成立しない。アプレットのコードがホストアプリのグローバル状態等にアクセスできてしまう。それ自体はModuleが無くてもクラスローダーを分離するような方法で対処できるかもしれないが、クラスローダーを上に辿っていく仕組みなどがありかなり複雑な問題になる。 クラス定義の公開とクラスのstatic状態の公開を分離して扱うという問題もある。 クラスはstaticメンバーを通じてグローバル状態を持っている可能性があり、それをアプレットやアドインから書き換えられていいのかという問題がある。 ユーザー定義クラスローダーでアドインを読み込んでもそれより上のクラスローダーで発見できるクラスはアクセスされてしまう。

Moduleシステムはjar hellの解決ではなく動的なモジュールロードを行うシステムにおいて役立つ可能性がある。実行時にセキュリティのために依存性をチェックできる。動的にロードされるjarのコードができることを限定できる。依存性解決ではなくセキュリティチェックのために依存性が記述される。

依存性という言葉がややこしい。jarをDLするいわゆるmavenの依存性解決と、Moduleの記述に違反するアクセスをしていないかというセキュリティチェックがある。 コンパイル時の依存性解決システムとランタイム時のモジュールシステムを区別する必要がある。 そしてランタイム時のシステムは動的設定が要求される可能性が高いのでpom.xmlは向いてない。 例えば特定の作者のアプレットに動的に権限を追加したいかもしれない。 まずpom.xmlはモジュールの公開範囲の設定に相当するものが無い。 仕様を拡張して対応できるかというと、問題がある。 pom.xmlは静的ファイルであると想定されるので、動的な公開範囲の設定に対応できない。

アノテーションで代替できるか? module-infoで公開範囲を設定するのではなく、公開するメソッドにアノテーションをつける。 より細かく制御できる一方でパッケージ全体を公開する場合手間がかかる。

ある記事ではMavenとModuleの違いについてModuleは実行時のセキュリティ目的の依存性チェックをサポートすると書いていたが、その主張はおかしい。MavenもJava標準として採用されたら実行時の依存性のチェックが可能だろう。Mavenに決してできないのは動的な依存性への対応。

そして私が提案したい事。 私のこの問題への理解は、1プロセス上で多数のJavaアプリを同時実行するための言語仕様及び処理系が必要になっているというもの。 そしてJVM上の疑似カーネルが解決策になる。 動的にアプレット/アドインをロードするようなシステムは疑似カーネルを必要としている。 従来、1台のコンピューター上で多数のプログラムが同時に動作しても破壊的な相互干渉を起こさないのはカーネルが管理しているから。 JVM上でも多数のプログラムの実行を管理して破壊的な相互干渉を防止するシステムが必要で、それが疑似カーネル。 Moduleではなく疑似カーネル、疑似プロセス、疑似プロセス間通信を実現する必要がある。 なお疑似スレッドはProject LoomのFiberが既にやっている。 疑似プロセスは他の疑似プロセスから独立したstaticメンバーの状態を持ち、その他あらゆるオブジェクトが分離されている。他の疑似プロセスとRPCをする。疑似プロセス間のRPCは実際には同一プロセス上で行われていてJITによって最適化される。他の疑似プロセスに公開するインターフェースは、クラス全体、パッケージ全体、あるいは個別に設定する。 Moduleのパッケージの公開設定は疑似プロセス間の通信で公開されるパッケージの設定になる。

さらにこのアイデアをもう一歩進めると、OSにただ1つJavaプロセスがあり全Javaアプリを同一プロセス上で実行する事が考えられる。 全Javaアプリが1プロセス上で実行される事でJITの有効性が高まる。ライブラリが共通ならその最適化を共通化できる。あと省メモリで起動が高速化する。 しかしセグメンテーション違反等でプロセスごと落ちるリスクがある。JDKの品質が問われる。

Moduleはリフレクションを通じたライブラリの非公開インターフェースへのアクセスを禁止できるが、ライブラリがオープンソースならカスタマイズプロジェクトを作ってModuleの公開設定を改変できてしまう。あるいはjarのバイトコードを改変する事もできる。それを防ぐ方法は無い。

Javaの複雑化_愚痴

言語は単純であるべきだが、複雑化する一方だ。 Javaはエコシステムが巨大で歴史が長いせいもあるだろうがどの領域にも複数の選択肢がある。

  • JavaエコシステムにはAWT, Swing, SWT, JavaFXと4種類のGUIフレームワークがあり、公式かつ最新のJavaFXがランタイムから分離されていて、古いSwingが同梱されている。
  • サードパーティライブラリも乱立している。しかも1つの領域に利用者数が多いライブラリが複数ある。
  • 継承か構成か?構成が推奨されるが相互参照が生じ、ユーザーコードによる構成にも問題を感じる。

このような状況はJavaソースコードを多様化させていく。 世界的なJavaソースコードの統一的記述が達成された方が可読性やプログラマーの均質性が高まる。

Javaエコシステムの複雑さのせいで、私はTenyuプロジェクトのソフトウェア構成の判断において色々な比較検討をさせられた。

Netty vs Grizzly 私はNettyを選んだ。Nettyはベンチマーク結果が良かったり実績が豊富だった。

libgdx vs jmonkeyengine vs JavaFX 私はjmonkeyを選んだ。3Dを主眼にしているようだったから。 JavaFXは3Dも出来るがゲーム用途では実績が無さすぎる。 なおここに挙げた以外でもマイナーなものがたくさんある。

2Dの簡単なゲームにJavaFXを使うというアイデアはよさそうに思う。2Dゲームを作るにしてもlibgdxかjavafxかという事になる。 http://almasb.github.io/FXGL/

JavaFXを使うにしてもFXMLかコードかで分かれる。JavaFXのscene builderを少し使っていたが、直接コードで書いた方が良いと判断した。

何にせよ選択肢が多い上に簡単に優劣をつけられないからJavaソースコードの多様化及びJavaプログラマーの不均質化の原因になる。せっかくの巨大エコシステムが無意味だ。エコシステム全体で重複したものを作っている。

プロジェクト間違い_問題

何かプログラムに問題があって解決する時、ライブラリに手を加えるべきところで、自分のアプリだけで独自解決してしまう問題。それをプロジェクト間違いと呼んでみた。どこにコードを書くかを間違えている。

例えば標準ライブラリのコードに問題があるからと独自にリフレクション等を駆使して解決が試みられる。 しかし、大元のプロジェクトへの修正と高速リリースによって解決されるべきだろうと思う。 とはいえ、そのような時難しいのは、自分のケースで解決するだけでなくより一般的な解決をする必要がある事で、それは独自の解決よりも一層難しくなる。

XodusやNetty等のサードパーティライブラリはリリースが高速でフィードバックしやすい。 実際にバグ報告をして修正され、すぐに最新版がリリースされた。

OS_状況メモ

Windowsを使い続ける理由は既存のソフトウェア資産なので、もしバーチャルプラットフォームなソフトウェアが増加するなら、脱Windowsが可能になる。 さらに、私はLinuxデスクトップ等FOSS系OSへの大規模な移行がありうると思っている。Tenyuの相互評価フローネットワークという構想はFOSSを収益化できる可能性があるからだ。

https://www.wired.com/2015/04/microsoft-open-source-windows-definitely-possible/ Windowsをオープンソースにするという話があるが、そうするくらいならソースコード非公開のまま無料化した方が良い。ソースコードの公開はセキュリティリスクを増大させる懸念があり、非公開である事はFOSS系OSに対する差別化になる。

FOSS系OS

  • ソースコード公開
  • 無料
  • カスタマイズ可能
  • ソフトウェアのみ

Windows

  • ソースコード非公開
  • 有料
  • カスタマイズ不可
  • ソフトウェアのみ

Mac OS X

  • ソースコード非公開
  • 有料?ハードウェアとセット
  • カスタマイズ不可
  • ハードウェアとセット。動作保証しやすい。

その他新しいマイクロカーネルOS。HarmonyOSやFuchsiaなどがある。

FOSS系OSはJDKを標準搭載しJavaアプリをメインに想定する戦略が有力かもしれない。そうする事で全FOSS系OSがアプリ資産を共有できて、FOSS系の弱さであるアプリ資産の乏しさをカバーできる。

Tenyutalk_案_独自ソフト

私はアランケイのOOPについて調べていてオブジェクト間メッセージングについてアイデアを得たので、Tenyuプロジェクトにそれを加える事にしました。これは当初の構想にありませんでしたが、結果的にTenyu基盤ソフトウェアの設計をより適切なものにしました。 もともと基盤ソフトウェアの一部の機能が"セキュリティ要件がほとんどないが高性能なP2P機能"を必要としていて、Tenyutalkはそれを実現し、さらにおおむねWWWを代替しうる仕様を持つ事も要件に入れます。 Tenyutalkはユーザー中心のネットでWWWを置き換えるためにあります。

要点

  • 単純なP2Pベースのシステム。署名された情報をやり取りするだけの単純なシステム。しかしTenyu基盤ソフトウェアが高度なP2Pシステムを持ちTenyutalkはそれを利用できる。
  • WWWのハイパーテキストはセマンティックではない。TenyutalkはJavaオブジェクトを通信し最高度のセマンティックがある。
  • WWWは高度な表現を持つWebページのためにHTML5等の仕様策定を必要としている。一方でTenyutalkはリポジトリクラスを継承した任意のクラスを動的にロードして使用するので、いちいち仕様策定する必要が無い。あるのは権限管理システム等のみ。
  • WWWで実現された事のほとんどが大勢のユーザーが作成したデータをサーバー上で1つのDBにまとめる事だった。peopleware。そして多数のサイトに自分が作成した情報が分散してしまっていた。Tenyutalkでは自分が作成したコンテンツは自分のPCに存在する。ただし一部データは他のユーザーのPCにキャッシュされる。
  • WWW全体で多数のサイトがユーザー管理システムやコメントシステム等を作成していた。TenyutalkではソースコードとDBの統合が行われる。つまり重複したソフトウェアを開発する必要が無い。
  • TenyutalkのGUIはあらゆるモデルを一貫した方法で閲覧できて、キーボードのみで高速に操作できることを念頭に設計している。他の操作方法にも対応する。デスクトップやモバイルに対応する。
  • Tenyutalkの標準モデルクラスはgithub上で管理され、誰でも自作のプログラムをPRで追加できる。この場合コードがレビューされるので全権限で動作できる。
  • 最小権限で動作するプログラムならだれでも自由にネットワークに流せる。
  • 一部の権限を必要とするプログラムは、ソースコードが公開されている場合に限り自由にネットワークに流せる。ただしセーフランチャーから起動してソースコードの公開や信用を確認する必要がある。
  • Tenyutalkのモデルクラスはリポジトリクラスの仮想メソッドを実装する必要がある。その中にJavaFXのGUIを作るメソッドもある。そのモデルの状態を表示する機能を実装する必要がある。さらにそれらGUI構築系メソッドは手元距離、デスク距離、展示距離等で分かれる。その他アイコンへの参照など全モデルクラスが備えるべきものがリポジトリクラスに定義され、あらゆるモデルが一貫した機能を備えるようになる。
  • 膨大な種類のモデルを扱えば、それはユーザー中心のネットを実現し、WWWを大部分置き換える可能性がある。
  • Tenyutalkは基盤ソフトウェアと同じプロセス上で動作する。
  • Tenyutalkは公開日時証明機能を持つ。
  • モデルを参照するためのクラスがある。これはWWWのURLに相当するもの。文字列表現もありうるが基本的にオブジェクトである。
  • 各モデルオブジェクトはP2Pネットワーク上でRPCする。これがアランケイのメッセージングから得たアイデア。例えばAのコンテンツに関連するコンテンツをBが作った場合、BはAにリクエストを送信し、AのコンテンツオブジェクトからBのコンテンツオブジェクトへの参照が自動的に作成される。これはかつてのブログのトラックバックと同様のシステム。ブログ記事が1つ1つオブジェクトでリポジトリクラスを継承している。リポジトリクラスにトラックバック対応のコードが書かれるので個々のモデルクラスに書く必要が無い。トラックバック用のAPIがRPCを通じて呼び出される。
  • 基盤と同じプロセスで実行されるので基盤のDBや機能を利用できて、例えばユーザーDBベースの暗号化通信ができる。
  • 自分のいずれかのリポジトリオブジェクトがメッセージを受信した場合にイベントが発生し、そのハンドラーを自作してTenyutalkに登録できる。ハンドラーアプレット。これはネットワークに流れず自分だけが使うものなので全権限で動作する。Tenyutalkはハンドラーアプレットに様々なAPIを提供する。このイベントとハンドラーアプレットのシステムによって通販システムを含むほとんどのWebシステムを代替しうる。
  • 横断的な検索や統計機能のため、基盤ソフトウェアを通じてサーバ役に指定されたノードに全ノードは更新を通知する。この仕組みはクローラー無しで全データのリアルタイムなインデックスを達成する。ちなみに純粋P2P型の検索システムを少し考慮したが性能やセキュリティ等を考慮すると無理筋と思ったのでやはり全体のデータを収集するサーバが必要と判断した。
  • あらゆるモデルで汎用的なインデックスデータのクラスが提供される。リポジトリはインデックスデータを取得する仮想メソッドを定義し、モデルクラスはそれを実装する必要がある。
  • 配信のような性能要件が厳しいサービスをどうp2pベースで実現するか?配信はある種のモデルクラスのオブジェクトとして配信者によって作成される。配信者はその配信オブジェクトの機能を通じて配信に関する設定をする。視聴者は配信者の所持オブジェクトの中から配信オブジェクトを選択する事で視聴開始できる。現在視聴中のユーザー一覧が配信オブジェクトに記録されるので、視聴者が膨大になった場合、新しい視聴者は配信者ではなく視聴者にアクセスする事でリレー配信を受ける事が可能。
  • モデルクラスやハンドラーアプレットはそのjarに任意のライブラリを同梱できる。さらにTenyutalkや基盤ソフトウェアが同梱しているライブラリは同梱せずとも使用できる。さらにもし実行時依存性解決が実装されたらそれを通じてライブラリを使用できる。
  • 短時間に大量のアクセスが1ノードに生じるとP2Pベースのシステムは弱いが、読み取りならリレー等で解決できる。従来、書き込みが殺到するケースはpeopleware系ドメインか、ネット炎上のケースがほとんどだったと思う。
  • Tenyutalkは新たなプログラミング環境を創出する可能性がある。
  • セマンティックな検索と従来のようなキーワード検索をどちらも実現できる。

P2Pはノードが任意のタイミングでオフラインになるのでC/SによるWWWと比較して可用性で劣るか? しかしC/Sはサーバが落ちるとそのサービスが利用できなくなる。 Tenyutalkで1ノードがオフラインになってもそのノードのユーザーが作成した情報が見れなくなるだけで他のノードの情報は見れる。 オフラインのユーザーによる新たな情報の作成はない。情報の作成を行うならPCを起動しそれに伴いオンラインになる。 だからP2Pによるユーザー中心コンピューティングはユーザーによる情報の作成機会を逃がさない。 しかしC/Sのサーバが落ちている時、誰かが新たに情報を作りたくてもそれが出来ない。C/Sは情報の作成機会を逃がす。 p2pではユーザーがオフラインになる直前の情報が最新情報であり、キャッシュシステムがあれば読み取りの可用性が低下しない。

リポジトリ指向_案

Tenyutalkというソフトウェアの設計をしていて、新しいプログラミングパラダイムを思いつき、それに基づいて設計を進める事にしました。それをリポジトリ指向と呼んでいます。 私がリポジトリと呼んでいるのはgitのリポジトリをオブジェクトレベルに持ち込み、さらに一般的と思われるいくつかの機能を追加した概念です。リポジトリはアランケイのメッセージングするオブジェクトに相当すると思います。 リポジトリは抽象クラスとして記述され、Tenyutalk上の全てのモデルクラスはそれを継承します。 リポジトリクラスはユーザー中心コンピューティングで扱われるあらゆるモデルクラスの基底クラスとなるよう設計されます。 リポジトリとオブジェクトを比較するとリポジトリは時間軸とブランチと人間による作成とメッセージングが特徴です。 リポジトリオブジェクトの状態はプログラムが自動的に作成するものではなく、人が更新内容を確認し1つ1つ承認します。

リポジトリ

  1. 検証や通信やGUIや永続化処理の仮想メソッドがある。
  2. 大抵のオブジェクトは時系列変化やブランチを持つので標準でそれら概念を扱う。
  3. 他人のリポジトリオブジェクトのAPIをRPCできる。
  4. リポジトリオブジェクトを参照するためのオブジェクトがある。
  5. 公開範囲と公開期間を設定できる。
  6. 親リポジトリを設定できる。
  7. コミットオブジェクトは1つのリポジトリまたはそれを祖先とするリポジトリへの更新の集合
  8. モデル毎に差分表示GUIを実装する
  9. 自動的なブランチ選択
  10. 関連する構造
  11. 再送信システム
  12. リアルタイム
  13. モデル例
  14. jarファイル

1 各モデルクラスはTenyutalk上にGUIを表示するためのメソッドを実装する。 例えば「私の現在状態」クラスでつぶやきを投稿するためのモデルクラスなら、つぶやきの内容等があるので、それを表示するようGUI表示メソッドを実装する。 他にモデルクラスは「動画」「記事」「画像」「音楽」など無数に考えられる。あるいは「ピックアップ」というモデルで他のモデルへの参照をいくつかまとめたものだったり。 そのGUIを通じてそのオブジェクトにメッセージを送れる。そのメッセージ作成GUI及び受信時処理を記述する。 永続化のためのストアクラスを実装する。 他にアイコンへの参照を定義する。

2 例えばツイッターは「私の現在状態」という1つの意味のデータに対して繰り返しコミットしてアップデートしているとみなせる。ツイート履歴はコミット履歴。 ブランチの必要性は、例えばツイートを英語版や日本語版などで分けたいかもしれない。国際的に活動するアカウントで良くある事として、日本人ユーザーのフォロワーが多いのに英語でツイートしたり、英語圏ユーザーが多いのに日本語でツイートしたり、混同させているという問題がある。 あるいは様々なソフトウェアにおいてバージョン3を開発している最中にバージョン2もバグ修正等でアップデートする場合がある。そのような場合、バージョン3と2はブランチが違う。 ブランチはエディションやメジャーバージョンの違いに対応するために使われる。 このような時系列データとブランチという概念は非常に多くのデータに見出せて、特に人間が他の人間のために作成する情報ではほとんど常に見出せる。

3 誰でもどのリポジトリにでもコミットできる。 リポジトリは管理者ユーザーが居て、その人が承認すればコミットが反映される。 コミットは最新版のオブジェクトが提出される。 gitと比べてコンフリクトが発生する可能性は同じ程度ある。 プロジェクト単位ではなくオブジェクト単位で管理されているので、オブジェクト単位でコミットが分散する。 オブジェクト単位でマージを管理する人が居るという事。

4 作者ユーザー名やクラス名やリポジトリ名やリビジョン番号やブランチ名を指定する。 参照はリビジョン番号やブランチ名を指定する事で不変になります。 参照オブジェクト

  • 総称型で参照先モデルのクラスを指定する
  • 参照先モデルのストアのクラス名
  • 参照先作成者ユーザーID。デフォルトでノード番号0にアクセスする。
  • リポジトリID
  • リビジョンID
  • ブランチ名
  • P2P URL出力メソッド
  • 強制キャッシュフラグ
  • ファイル強制キャッシュフラグ。参照先にファイル参照クラスがあった場合ファイルもキャッシュされる
  • オプション値。任意文字列。被参照オブジェクトによって意味が変わる。
  • 予備ノード一覧。参照先作成者ユーザーにアクセスできない場合、ここにアクセスする。

各モデルはファイルを扱う場合汎用ファイルクラスを使う。クラス設計でメンバー変数にファイルを使う場合。 ファイル参照クラス 汎用

  • ファイルサイズ
  • ハッシュ値
  • ファイル名。Tenyutalk下の相対パス。
  • Apache Tikaによるmimetype判定

ファイルリポジトリクラス。汎用

  • 1つのファイル参照クラス

多数のファイルを扱うには親オブジェクトを設定することによる複数のファイルリポジトリクラスのツリーを扱う。 実際、そのリポジトリの作成はGUIからアップロードするフォルダを指定して内部的に処理される。

5 情報流出の懸念はあるが、一応公開範囲を設定できる。 公開範囲は予め設定しておいたユーザー集合を指定する。非公開と完全公開は最初から指定できる。一部のユーザーへの限定公開が選べるが、そのユーザー集合を予め作成しておく。 公開期間を過ぎると他のノードが持っていたキャッシュも削除される。

6 リポジトリは親リポジトリへの参照を持つ場合があり、いくつかの実装を親リポジトリに委譲する。例えば子リポジトリの管理者は親リポジトリの管理者になる。 親リポジトリへの参照が設定されるとそのリポジトリは親リポジトリに従属し、管理権限等を親リポジトリから継承する。 本来の管理者は親リポジトリの変更権を持ち続け、親リポジトリへの参照をnullにすれば管理権限を取り戻せる。 これによって多数のリポジトリを従えた1個のリポジトリツリーを作る事ができて、ファイルシステムに相当する事が可能になる。 リポジトリは子リポジトリ一覧を持つ。 複数のリポジトリを従えたリポジトリにブランチを作る場合、全ての子孫リポジトリにも一斉にそのブランチを作成できる。 つまりリポジトリツリーに再帰的に操作を加えれる。

7 コミットオブジェクトは作成者ユーザーIDや説明文や更新オブジェクト集合で構成される。 更新オブジェクトはブランチ名や前提リビジョン番号や最新オブジェクトで構成される。 コミットが承認されると複数のリポジトリが一斉に更新される。 もし同じリビジョン番号に複数のコミットが行われた場合コンフリクトになるが、モデル毎に固有のマージ処理を実装する。そのデフォルト実装は後にコミットされた方を破棄する。 多人数開発のシステムで1つのリポジトリに多人数がコミットないしプルリクする場合、その中の1つをマージすると、他のコミットはそれがマージされた後のプロジェクトの状態で動作確認されていない。 この問題はgitやgithubでも存在していると思う。 リポジトリは1人のメイン管理者が居て他の貢献者のコミットペースが緩やかである必要がある。

8 モデル毎に差分表示GUIを実装できる。 変更されたメンバー変数だけを表示、比較するようなGUI。 長文のメンバー変数なら変更された箇所のみを表示 画像なら変更された部分を表示。

9 プログラムがリポジトリの参照を辿りながら自動的に探索するとき、探索中に遭遇したリポジトリが複数のブランチを持っていた場合、どのブランチを選択するか選ぶ必要がある。

その探索の文脈情報に選択すべきブランチ名がある場合。 多数のリポジトリでブランチ名が共通化されているとブランチを自動選択できる。 例えば日本語ブランチとEnglishブランチがある場合にユーザーの言語設定に応じて自動的に選択できる。 複数のリポジトリを従えたリポジトリでブランチを作成した場合の再帰的なブランチ作成によって共通のブランチ名を持たせる事ができるが、探索においてそのブランチ名を指定できる。

参照がブランチ名を指定している場合。 探索がそれを無視するか従うか、探索時に指定できる。

リポジトリ側が探索の文脈情報を受け取って推奨されるブランチを決定する場合。

10 リビジョン別オブジェクトのクラス定義。モデル毎に用意される

  • ソースコード。Tenyutalk上でモデルアプレットのソースコードを見れる事。
  • 各種GUI作成メソッドの実装。簡易、詳細。手元距離、デスク距離。
  • chainversionupメソッドの実装。規約とリフレクションを使う事で多数の具象クラスがその抽象クラスRepositoryの変更に耐えれるようにする。
  • シリアライズ、デシリアライズメソッドの実装
  • テストクラス。ランダムな状態の作成及びテスト。

リポジトリ

  • 親リポジトリ。nullの場合も
  • このリポジトリの更新が通知されるリスナーリポジトリ一覧
  • このリポジトリに更新を通知する観察リポジトリ一覧
  • ブランチMap
  • 連動削除フラグ。オリジナルが削除されたらキャッシュも削除されるか
  • 合計いいね
  • エロ、グロ、暴力等を含むかフラグ
  • タグ。タグは継承関係を持つ。タグはリビジョン別。
  • オフラインフラグがtrueなら一切ネット上にデータが送信されない。
  • 代理アップロードフラグ。アップロード者が作者ではないファイルの場合。
  • 閲覧情報。誰がいつ閲覧したか。対象オブジェクトのハッシュ値への署名を持つ。公開日時証明になる。
  • 文字列コピー機能。MD記法でモデルを文字列化する。

ブランチ

  • リビジョン別オブジェクト一覧

リビジョン別オブジェクト

  • 動機付けられた(返信先)リポジトリへの参照
  • 署名
  • いいね

ストアクラス 基盤ソフトウェアと大体同じ設計。ただしSnappyで圧縮。リポジトリが冗長なデータが多いので

TenyutalkAPI

  • リポジトリ閲覧履歴
  • 受信した更新通知履歴
  • 検索履歴
  • 他リポジトリへのメッセージ送信。暗号化送信も
  • フォルダパス取得。ここにファイルを作成したりできる
  • DBパス取得。
  • ファイル再生。ファイルの形式を特定して形式別にGUI表示する。
  • ファイル再生ボタン。ファイルの形式に応じたボタンをGUI表示する。
  • DLメソッド。汎用ファイルクラスを指定してそのファイルをDLする。ファイルサイズまたは強制キャッシュフラグに応じて場合によってキャッシュする。

11 リポジトリは互いにメッセージングするが、相手側のノードがオフラインの場合、再送信システムに登録される。 再送信システムは両者がオンラインになった場合にメッセージを届ける。 この仕組みはP2Pノードが頻繁にオフラインになる問題に対応する。

12 誰がどのオブジェクトを閲覧しているかリアルタイムに把握できて、 オブジェクトが更新されたらリアルタイムに通知される。 さらに、チャットシステムをあらゆるモデルが備える。 任意のユーザーを指定して、現在そのユーザーが見ている情報が何かわかる。

13 ホームリポジトリで任意のリポジトリをフォローできる。 フォローすると更新が通知される。 フォロー先リポジトリの子オブジェクトの更新も通知される。

問いリポジトリは、従来のような検索から脱却し、問いを登録し、その問いへの答えを誰でも登録できるようにする。 既知の問いを検索できる。

14 モデルクラスの定義が含められたjarファイルは、基盤ソフトウェアの起動時に特定フォルダから読み込まれる。 さらに動的にロードされる。 Tenyutalkのjarを読み込むタスクが定期的に実行されていて、そのフォルダに新たなjarファイルが設置されていたら読み込む。 Tenyutalkのモデルクラス専用のクラスローダーが基盤ソフトウェアのプロセス上で管理される。 シリアライザはKryoだが、Kryoは独自のクラスローダーを使用できる。 unregistered classの解決にのみ使用されるので、Tenyutalkのモデルクラスのインスタンスはシリアライズされた時その完全修飾名を持つ。 そもそもTenyutalkは動的にモデルクラスを追加していかないといけないので全ノードで共通のクラス識別子は完全修飾名しかなく、その仕様はKryoによるものである以前にTenyutalkによるものである。 そしてデシリアライズされたクラスはRepositoryクラスのメソッドを通じて利用される。そのオーバーライドによって固有の動作を提供する。