&Notepad

Will Crichton – September 9, 2018
私は “システム・プログラミング” という言葉に不満があります。 私には、それは常に、低レベルのプログラミング(マシンの実装の詳細を扱う)とシステム設計(相互運用するコンポーネントの複雑なセットを作成し管理する)という2つの考えを不必要に組み合わせているように見えました。 なぜそうなのでしょうか? いつからそうなってしまったのでしょうか? そして、システムという考え方を再定義することで何が得られるのでしょうか。

1970 年代。 アセンブリの改良

この用語がどのように進化したかを理解するために、現代のコンピューター システムの起源にさかのぼってみましょう。 誰が最初にこの言葉を作ったのかはわかりませんが、検索してみると、「コンピュータ システム」を定義するための本格的な取り組みは、70 年代初頭ごろに始まったことがわかります。 System Programming Languages (Bergeron1 et al. 1972) の中で、著者らは次のように述べています:

A system program is an integrated set of subprograms, together forming a whole greater than the sum of its parts, andexexceeding some threshold of size and/or complexity. 典型的な例としては、マルチプログラミング、翻訳、シミュレーション、情報管理、時間共有のためのシステムなどがある。 6500>

  1. 解決すべき問題は、多くの、そして通常は非常に多様なサブ問題からなる広範な性質のものである。
  2. システムプログラムは他のソフトウェアやアプリケーションプログラムをサポートするために使用されることが多いが、それ自体が完全なアプリケーションパッケージである場合もある。
  3. システムプログラムは、モジュール内とモジュール間(すなわち「コミュニケーション」)の両方で一定の規律や構造を必要とし、通常は複数の人によって設計され実装される。 しかし、この定義は主に記述的である一方、この論文の重要な考えは規定的であり、システム言語から低レベル言語を分離することを提唱しています(当時は、アセンブリと FORTRAN を対比していました)。 このような言語は、高レベル言語の簡潔さと読みやすさに、アセンブラ言語で得られる空間と時間の効率、マシンとオペレーティングシステムの機能を「手に入れる」能力を組み合わせたものでなければなりません。

同じ頃、CMU の研究者たちは BLISS: A Language for Systems Programming (Wulf et al. 1972) を発表し、BLISS を次のように説明している:

私たちは BLISS を「実装言語」と呼んでいるが、おそらくすべてのコンピュータ言語は何かを実装するのに使われるのでこの言葉は多少あいまいであると認めている。 私たちにとってこの言葉は、特定のアプリケーション、つまり特定のマシンのための大規模な生産ソフトウェア システムを書くことに主眼が置かれた、汎用的な高水準言語を意味します。 コンパイラのような特殊用途の言語はこの範疇には入らないし、これらの言語が必ずしも機械に依存しないことを前提としているわけでもない。 この定義では、”実装 “という言葉を強調し、”設計 “や “文書 “といった言葉は使っていない。 我々は、実装言語が大規模なシステムの初期設計を表現するための適切な手段であるとも、そのシステムの独占的な文書化のための手段であるとも、必ずしも考えていないのである。 マシンに依存しない、設計と実装を同じ表記法で表現する、自己文書化などの概念は明らかに望ましい目標であり、我々が様々な言語を評価する基準である。

ここで著者は、「実装言語」はアセンブリよりも高レベルであるが「設計言語」よりも低レベルであるという考えを対比させている。 これは、前論文の定義に抵抗し、システムの設計とシステムの実装は別々の言語を持つべきだと提唱している。

これらの論文はどちらも研究成果物または提唱者である。 最後に考えるべきは、(やはり生産的な年である 1972 年の)Systems Programming (Donovan 1972) で、システム・プログラミングを学ぶための教育テキストです。

システム・プログラミングとは何でしょうか。 コンピュータというと、すべての命令に従うある種の獣のようなものをイメージされるかもしれません。 コンピュータは基本的に金属でできた人間であるとか、逆に人間は生身の人間でできたコンピュータであると言われることがある。 しかし、コンピュータを身近に見てみると、基本的には非常に特殊で原始的な命令に従う機械であることがわかる。 コンピュータの初期には、原始的な命令を表すスイッチのオン・オフで、人はコンピュータとコミュニケーションしていた。 しかし、やがて人々は、より複雑な指示を与えたいと思うようになります。 例えば、「X=30×Y、Y=10とすると、Xはいくらか? 現在のコンピュータは、システムプログラムの助けを借りなければ、このような言語を理解することはできない。 システムプログラム(コンパイラ、ローダ、マクロプロセッサ、オペレーティングシステムなど)は、コンピュータをユーザーのニーズに合わせてより良く適応させるために開発されたものである。 さらに、人々は、プログラムを準備する仕組みについて、より多くの支援を求めていました。

この定義は、たとえそれがエンド ユーザーに直接さらされないインフラであっても、システムは人々の役に立っていることを思い出させてくれる点が気に入っています。 スクリプトの台頭

70年代および80年代には、ほとんどの研究者はシステム プログラミングを通常アセンブリ プログラミングとの対比として見ていたように思います。 単に、システムを構築するための良いツールが他になかったのです。 (この中でLispがどのような位置を占めていたかは分かりませんが? 私が読んだ資料のどれもが Lisp を引用していませんでしたが、Lisp マシンが一時的にでも存在したことは漠然と知っています)

しかし、90 年代半ばに、動的型付けスクリプト言語の台頭により、プログラミング言語に大きな変化が起こりました。 Bash のような初期のシェル スクリプト システムを改良し、Perl (1987), Tcl (1988), Python (1990), Ruby (1995), PHP (1995), および Javascript (1995) といった言語が主流となりました。 このような流れは、影響力のある論文「スクリプティング」で最高潮に達しました。 21世紀の高級プログラミング」(Ousterhout 1998)という影響力のある記事で最高潮に達しました。 これは、「システム プログラミング言語」と「スクリプト言語」の間の「Ousterhout の二項対立」を明確にしたものである。

スクリプト言語は、システム プログラミング言語とは異なるタスク用に設計されており、これが言語の根本的な違いにつながっている。 システム・プログラミング言語は、データ構造やアルゴリズムをゼロから構築するために設計されており、メモリの単語といった最も原始的なコンピュータ要素から出発する。 それに対して、スクリプト言語は、強力なコンポーネントの集合を前提とし、コンポーネント同士をつなぐことを主目的とした、グルーイング(接着)用に設計された言語である。 システムプログラム言語は、複雑さを管理するために強く型付けされる。一方、スクリプト言語は、コンポーネント間の接続を単純化し、迅速なアプリケーション開発を可能にするために型付けをしない。 より高速なマシン、より優れたスクリプト言語、グラフィカルユーザーインターフェイスとコンポーネントアーキテクチャの重要性の増加、およびインターネットの成長など、最近のいくつかの傾向は、スクリプト言語の適用性を大幅に増加させた。 設計レベルでは、彼は各言語クラスの新しい役割を特徴づけた。システム プログラミングはコンポーネントを作成するためのものであり、スクリプトはそれらをつなぎ合わせるためのものである」

この頃、静的型付けだがガベージ コレクション言語も人気を集め始めている。 Java (1995 年) と C# (2000 年) は、今日私たちが知っている巨人へと変貌を遂げました。 この2つは伝統的に「システムプログラミング言語」とは見なされていませんが、世界最大のソフトウェアシステムの多くを設計するために使用されてきました。 Ousterhout は「今形成されているインターネットの世界では、Java はシステムプログラミングに使われている」とまで明言しています。

2010 年代。 境界が曖昧になる

この10年間で、スクリプト言語とシステムプログラミング言語の間の境界が曖昧になり始めました。 Dropbox のような企業は、Python だけで、驚くほど大規模でスケーラブルなシステムを構築することができました。 Javascript は、何十億もの Web ページでリアルタイムの複雑な UI をレンダリングするために使用されています。 Python、Javascript、その他のスクリプト言語では、静的型情報を徐々に追加することで、「プロトタイプ」コードから「プロダクション」コードへの移行を可能にする漸進的型付けが盛んになっている。

同時に、静的言語 (Java の HotSpot など) と動的言語 (Lua の LuaJIT、Javascript の V8、Python の PyPy など) の両方の JIT コンパイラーに膨大なエンジニアリング リソースが注がれ、そのパフォーマンスは従来のシステム プログラム言語 (C や C++) と競合できるようになった。 Sparkのような大規模な分散システムはScala2で書かれている。 Julia、Swift、Go などの新しいプログラミング言語は、ガベージコレクション言語におけるパフォーマンスの限界を押し広げ続けています。

「2014 年以降のシステム プログラミング」と呼ばれるパネルでは、今日の自称システム言語を支える最大の頭脳が紹介されました。 Bjarne Stroustrup (C++ の開発者)、Rob Pike (Go の開発者)、Andrei Alexandrescu (D の開発者)、Niko Matsakis (Rust の開発者)です。 2014年のシステムプログラミング言語とは」という質問に対して、彼らはこう答えた(編集部転記):

  • Niko Matsakis氏。 クライアントサイドのアプリケーションを書くこと。 Goが対象としているものとは正反対です。 これらのアプリケーションでは、高いレイテンシが要求され、高いセキュリティ要件があり、サーバー側では出てこない多くの要件があります。 システム・プログラミングは、ハードウェアを扱う分野から生まれたもので、その後、アプリケーションはより複雑になりました。 複雑さに対処する必要があるのです。 もし、リソースに大きな制約がある場合は、システム・プログラミングの領域です。 より細かい制御が必要な場合も、システム・プログラミングの領域です。 システム・プログラミングかどうかは、制約条件によって決まるのです。 メモリが足りないのか? 6466>
  • Rob Pikeです。 最初に発表したとき、私たちは Go をシステム プログラミング言語と呼びましたが、多くの人が Go をオペレーティング システムを書く言語だと思い込んでしまったので、そのことを少し後悔しています。 というのも、多くの人がこれをオペレーティングシステムを書く言語だと思い込んでいたからです。 今は、クラウドインフラストラクチャの言語だと理解しています。
  • Andrei Alexandrescu: システム・プログラミング言語であるかどうかを確認するためのリトマス試験紙がいくつかあります。 システム・プログラミング言語は、その中で独自のメモリ・アロケータを書けるものでなければなりません。 ハードウェアはそうやって動くので、数字をポインタに偽造できることです。

それでは、システム・プログラミングは高性能なものなのでしょうか。 リソースの制約? ハードウェアの制御? クラウドインフラ? 大雑把に言うと、C、C++、Rust、Dといったカテゴリの言語は、マシンからの抽象度という点で区別されるような気がします。 これらの言語は、メモリ割り当て/レイアウトやきめ細かいリソース管理など、基礎となるハードウェアの詳細を公開します。

別の考え方として、効率の問題があるとき、それを解決するのにどれだけの自由度があるでしょうか。 低レベルのプログラミング言語の素晴らしいところは、非効率を特定したときに、マシンの詳細を注意深く制御することにより、ボトルネックを解消することができる点です。 この命令をベクタライズする、このデータ構造をキャッシュに残すためにサイズを変更する、といった具合に。 静的型が「私が追加しようとしているこれら 2 つのものは間違いなく整数である」という確信3 を与えてくれるのと同じように、低レベル言語は「このコードは私が指定したとおりにマシン上で実行される」という確信を与えてくれます。 ランタイムが一貫して期待通りの方法でコードを実行するかどうかを知ることは、信じられないほど困難です。 これは、自動並列化コンパイラとまったく同じ問題で、「自動ベクトル化はプログラミング モデルではない」 (ispc の物語を参照) と言われています。 Python でインターフェイスを書いていて、「この関数を呼び出す人が私に int をくれることを確かに願うよ」と考えているようなものです。 …so what is systems programming?

ここで、私の最初の不満に戻ります。 多くの人がシステム・プログラミングと呼ぶものを、私は低レベルのプログラミング、つまり、マシンの詳細を明らかにすることだと考えています。 しかし、それではシステムについてはどうでしょうか。

  1. 解決すべき問題は、多くの、そして通常は非常に多様なサブ問題からなる幅広い性質のものである。
  2. It is likely be continuously evolving in the number and types offeatures that supports.
  3. A system program requires a certain discipline or structure, both within and between modules (i.e., “communication”), and is usually designed and implemented by more than one person.

These seem more much like software engineering issues (modularity, reuse, code evolution) than low-level performance issues.These is a lot more like software engineering problems (modularity, reuse, code evolution). つまり、これらの問題への対処を優先するプログラミング言語は、システム プログラミング言語であるということです! とはいえ、すべての言語がシステム・プログラミング言語というわけではありません。 動的な型や「許可ではなく許しを請う」といったイディオムは、優れたコード品質には貢献しないからです。

では、この定義から何がわかるでしょうか。 OCaml や Haskell のような関数型言語は、C や C++ のような低レベル言語よりもはるかにシステム指向である、ということです。 学部生にシステム・プログラミングを教える際には、不変性の価値、インターフェース設計の改善における豊富な型システムの影響、高階関数の有用性といった関数型プログラミングの原則を含めるべきである。 学校はシステムプログラミングと低レベルプログラミングの両方を教えるべきです。

提唱されているように、システムプログラミングと優れたソフトウェア工学は区別されるのでしょうか。 そうではありませんが、ここでの問題は、ソフトウェア工学と低レベルのプログラミングがしばしば分離して教えられていることです。 ほとんどのソフトウェア工学のクラスは通常、Java を中心とした「良いインターフェイスとテストを書きなさい」というものですが、私たちは、リソースに大きな制約のあるシステムを設計する方法についても学生に教えるべきでしょう。 おそらく、最も興味深いソフトウェアシステムの多くが低レベルであることから、低レベルプログラミングを「システム」と呼ぶのでしょう(例:データベース、ネットワーク、オペレーティングシステムなど)。 低レベルのシステムには多くの制約があるため、その設計者は創造的に考える必要があります。

もうひとつの枠組みは、低レベル プログラマーは、システム設計におけるどのようなアイデアを現代のハードウェアの現実に対処するために適応させることができるかを理解しようと努めるべきであるということです。 この点において、Rust コミュニティは非常に革新的であり、優れたソフトウェア設計/機能的プログラミングの原則を低レベルの問題 (たとえば、futures、エラー処理、あるいはもちろんメモリ安全性) にどのように適用できるかを検討していると思います。 分野としてのコンピュータ システム設計は、それ自身の名前を持たないにはあまりにも重要です。 この 2 つのアイデアを明確に分離することで、プログラミング言語設計の空間がより概念的に明確になり、また、2 つの空間を越えて洞察を共有する扉が開かれます。

Please direct comments to my inbox at [email protected] or Hacker News.

  1. Cool fact here: この論文の著者である R. Bergeron と Andy Van Dam はグラフィックス コミュニティと SIGGRAPH カンファレンスの創立メンバーです。 グラフィックスの研究者がシステム設計のトレンドを作るという、継続的なパターンの一部です。

  2. Mandatory link to Scalability !

  3. 理想的には静的型は100%の保証(または返金)ですが、実際にはほとんどの言語がある程度のObj.magicを許可しています。

コメントを残す

メールアドレスが公開されることはありません。