バトラー・ランプソンとゼロックスPARCのアイデア(ネットワーキング、OS設計、ネーミング、キャッシュ、RPC)がなぜ今でも大規模システム設計に有用かを実践的に解説します。

バトラー・ランプソンは過去半世紀で最も影響力のあるコンピュータシステム設計者の一人でした。1970〜80年代のゼロックスPARCで、彼はネットワーク化されたコンピュータが孤立したマシンではなく、プログラム、ファイル、プリンタ、人が信頼してやり取りできる共有環境の一部として振る舞うべきだという考えを形作りました。
ランプソンの仕事が長持ちする理由は、基本に立ち返っている点です:スケールするインターフェイス、合成可能なメカニズム、現実世界の障害を例外として扱わないシステム設計。
「スケール」は単に巨大なデータセンターがあることを指しません。多くのユーザー、多くのマシン、現実世界の混乱があるときに起こる事象です。考えてみてください:数百台のノートPCとサービスがログインやファイルを共有するオフィス、同時に何千人もの顧客が使うプロダクト、あるいはサーバが落ちたりネットワークが遅くても動き続けなければならない社内アプリなど。
その時点で、問題は変わります。「自分のマシンで動くか?」ではなく、次のような問いを立てます:
これはノスタルジーや小ネタの巡回ではありません。ランプソンの仕事が有益なのは、堅牢な設計思想(小さくて明快なインターフェイス、単純な構成要素、障害を前提にした設計)を生み出したからです。
ここでは現代のOSや分散コンピューティングに受け継がれた概念――ネットワーキング、RPC、ネーミング、キャッシュ、実用的なセキュリティ――に焦点を当て、今日のアーキテクチャでこれらのパターンを見分け、自分のサービスに応用する方法を示します。
各人の机に強力な個人用コンピュータがあり、共有サービスにつながって職場全体が一貫したシステムのように感じられる――それがPARCの賭けでした。目的は単体の画期的な装置ではなく、一日中使える実用的なセットアップを作ることでした。
PARCは、日常作業(執筆、設計、ファイル共有、印刷、コラボレーション)に適した個人用コンピューティングを実用化しようとしました。目標は特別な操作や儀式を必要としない、実用的な作業環境です。
Altoは「パーソナル」部分:対話作業に向けたコンピュータ。イーサネットは「職場」部分:Altosが互いに、そして共有リソースと高速にやり取りできるネットワーク。
共有リソースは単なるオプションではありませんでした:
この組み合わせは新しいメンタルモデルを促しました:マシン単体で強力でも、信頼してネットワークサービスを利用できるときに劇的に有用になる。
PARCはプロトタイプや孤立したデモで終わりませんでした。ハードウェア、OS、ネットワーキング、アプリケーションを含む完全なシステムを組み立て、人々が実際にどう働くかから学びました。
そのフィードバックループは、実運用でしか現れない難問を明らかにしました:ネーミング、過負荷処理、障害対応、性能の予測可能性、共有リソースを「近く」に感じさせること。
多くのPARCシステムは「単純なプリミティブ + 厳格なエンジニアリング」の組合せという認識可能なアプローチを反映しています。インターフェイスは小さくわかりやすく、サービスは合成可能に作り、本番に近い環境でアイデアを試す。こうした作法が今日のチームでも役に立つ理由です。
Altoは単なる「机上のコンピュータ」ではありませんでした。個人用マシン、高品質なグラフィカルUI、共有リソースに接続する高速なローカルネットワークという三つの考えを一体化した点で画期的でした。
この組合せは期待値を書き換えました。マシンはユーザーに属するレスポンシブな存在でありながら、共有ファイルサーバやプリンタ、コラボレーションツールへの入口でもある、と感じさせたのです。これがクライアント/サーバ思考の種です。
Alto以前は、計算は「機械に行く」か端末を使うことを意味することが多かった。Altoはそれを覆しました:クライアントはユーザーと共にあり、ネットワークは共有能力を身近にします。
実務では「クライアント/サーバ」は図ではなくワークフローでした。低遅延で即時性が必要な作業はローカルで行い、共有や複製が非現実的な仕事はリモートに置く。
「Alto」を「ラップトップ」、「ファイル/プリントサーバ」を「クラウドサービス」に置き換えても、メンタルモデルは馴染み深いものです。デバイスはUIを描画し、データをキャッシュし、短いレイテンシのやり取りを処理するクライアント。クラウドは共有状態、コラボレーション、集中管理ポリシー、弾力的な計算を提供するサーバ側。
良いシステムはこの分割を受け入れます。ユーザーはローカルの応答性とオフライン耐性を望み、組織は共有の真実と調整されたアクセスを望むのです。
この分割はOS設計者に恒常的な緊張を与えます:\n\n- ローカルの応答性: UIはネットワークを待てない。\n- ネットワーク上の一貫性: 共有ファイルや識別、権限は複数クライアントが同時に振る舞っても予測可能であるべき。
PARC時代の作業は、ネットワークをコンピュータの一部と仮定すると、この緊張を早期に顕在化させました。ローカルとリモートを「同じ」と装うのではなく、ローカルに感じさせつつ現実の違いを設計で埋める必要があると示したのです。
イーサネットは「単なるネットワーキング」に見えがちですが、PARCでは部屋の中の多くのマシンを共有システムとして振る舞わせる実用的な突破口でした。
イーサネット以前は、コンピュータ接続は高価で専用のリンクを必要とすることが多かった。イーサネットは比較的安価で多くのマシンが同じ媒体に接続できる方式を提供し、協調が豪胆なインフラを要求しなくなりました。
加えて、イーサネットの共有性は新しい設計を促しました:サービスは別マシンに置ける、プリンタやファイルサーバはネットワーク接続できる、チームは接続が稀ではないため迅速に反復できる。
今日ではネットワークはメモリやストレージと同等に扱われます。アプリの「ローカル」動作はリモート呼び出し、リモートデータ、リモートの識別、設定に依存することが多いです。
この前提を受け入れると、ネットワークが適当に動くことを期待して設計することはやめます。
共有ネットワークは競合を生みます。パケットは遅延、喪失、順序入れ替わりが起きます。ピアは再起動する。スイッチは過負荷になる。何も「壊れて」いなくてもシステムは壊れたように見えます。
だから、正しい姿勢は「不完全な条件下でも通常動作するように作る」ことです:\n\n- 早期に計測を入れる:ログ、基本的なメトリクス、リクエストトレース\n- タイムアウトをデフォルトにする\n- 再試行はバックオフと上限を設けて設計し、復旧が輻輳を増幅しないようにする
イーサネットは分散コンピューティングを可能にしましたが、同時に分散系が要求する規律も強制しました。
PARCで「サービス」とは、ネットワーク上の他者のために1つの仕事をするプログラムを意味しました。
ファイルサービスは文書を保存・返却し、プリントサービスは文書を受け取って紙を出力し、ディレクトリ(ネーミング)サービスは機械の詳細を覚えていなくても正しいファイルサーバやプリンタ、人を見つけられるようにしました。各サービスは目的が明確で、定義済みのインターフェイスを持ち、利用者(人や他のプログラム)が依存します。
大きなシステムを小さなサービスに分けると変更が安全かつ迅速になります。印刷に新機能が必要なら印刷システムだけ進化させればよく、ファイル保存の再設計は不要です。境界は責任を明確にします:「ここにファイルがある」「ここで印刷が行われる」など。
またサービスはインターフェイスを先に設計する習慣を促します。プログラムが別マシンと話す必要があるとき、入力・出力・エラーを明確にする必要があり、モノリス内部で曖昧にされがちな詳細が外に出ます。
サービスが増えるとネットワーク呼び出しも増え、遅延が増え、負荷や新しい障害モードが出てきます:ファイルサービスは生きていてもプリントサービスは落ちている、ディレクトリが遅い、など。
モノリスは「一度に全部死ぬ」が、分散サービスは部分的で混乱した失敗をする。解決策はサービスを避けることではなく、部分的障害に明示的に設計することです。
多くのクラウドアプリは内部サービス群として動きます:アカウント、課金、検索、通知など。PARCの教訓は今も有効です:明確さと独立した進化のために分割するが、初日からネットワーク遅延と部分的な障害を想定して計画する。
実務的にはサービス境界に基本的なタイムアウト、再試行、明確なエラーメッセージを組み合わせることが多い(参照: /blog/failure-is-normal)。
RPCは「他のマシンの関数をあたかもローカル関数を呼ぶように呼べる」単純だが効果の大きい考えです。リクエストを手でパッケージして送ってレスポンスを解凍する代わりに、RPCはプログラムが「getUser(42)を実行して」と言えばシステム側がメッセージ送受信を処理してくれます。
「身近に感じさせる」ことはPARCの分散コンピューティング作業の中心であり、今日のチームが求めるものでもあります:明確なインターフェイス、予測可能な振る舞い、アプリケーションコードに露出する部品の削減。
RPCの危険は、それが通常の関数呼び出しとあまりに似てしまうことです。ローカル呼び出しは成功するかプロセスをクラッシュさせますが、ネットワーク呼び出しは遅くなったり、消えたり、部分的に完了したり、成功しても通知が来ないことがあります。良いRPC設計は次を組み込みます:
タイムアウトや応答の喪失は再試行を避けられないため、イデンプテント性が重要です:一度行っても複数回行っても結果が同じ操作です。\n\n例:chargeCreditCard(orderId, amount)はデフォルトではイデンプテントではありません。タイムアウト後に再試行すると二重課金される恐れがあります。より安全な設計はchargeCreditCard(orderId)のように orderId が請求を一意に識別し、サーバが重複を「既に済んでいる」と扱えるようにすることです。
現代のAPIはRPC的発想の直系です。gRPCは型付きメッセージと明確なインターフェイスで「リモートメソッド呼び出し」を明示的にします。RESTはリソース指向の様相を取ることが多いですが、目的は同じ:通信を標準化し契約を定め失敗を管理すること。
様式がどうであれPARCの教訓は変わりません:ネットワークは道具であって無視すべき詳細ではない。良いRPCは分散を便利にしますが、それがただで手に入ると装わないようにします。
分散システムは「見つからない」ときに壊れたように感じます。
ネーミングが難しいのは現実世界が静止していないからです:マシンは置き換わり、サービスは別ホストへ動き、ネットワークは再番号化され、人々は「ファイルサーバ」や「LaserWriterに印刷」のような安定した、覚えやすいパスを期待します。名前と場所が結びついていると、変更のたびにユーザーに目に見える停止が起きます。
PARC時代の重要な考えは、**欲しいもの(name)と現在どこにあるか(location)**を分離することです。名前は安定で意味のあるものであるべきで、場所は実装の詳細として変わり得ます。
この二つが融合すると脆弱なシステムになります:ショートカット、ハードコードされたIP、設定のドリフトが生じます。
ディレクトリサービスは「Xは今どこ?」に答えて名前を場所(および型、所有者、アクセスルールのようなメタデータ)に写像します。良いディレクトリは単なるルックアップを保存するだけでなく、組織の運用をエンコードします。
優れたネーミング/ディレクトリ設計に共通する実用的特性:\n\n- 安定性: ハードウェア更新や移行に耐える名前\n- 委譲: チームが自分のサブツリーを管理できる\n- キャッシュ: クライアントは無駄な往復を避けるために答えを保持する\n- 更新と鮮度: 変更は安全に伝播し、キャッシュが古い答えを信頼できる期間のルールを持つ
DNSは古典例です:人間に優しい名前が変わりうるIP群へ写像され、TTLでキャッシュが制御される。社内では「service-a.prod」のようなサービスディスカバリが同じパターンを繰り返します:安定したサービス名、変化するインスタンス、キャッシュ性能と更新速度の間の緊張。
スケールし、理解可能なシステムを望むなら、ネーミングを第一級の設計課題として扱ってください。後回しにしてはいけません。
キャッシュは単純です:一度取得した近くのコピーを保持して次を速くする。ネットワーク越しや遅いディスク、忙しいサーバに毎回問い合わせる代わりにローカルコピーを再利用します。
PARCでは、ネットワークワークステーションと共有サービスの組合せにより「またサーバに訊く」習慣が高価になったため、キャッシュはリモート資源を「速く感じさせる」ために重要でした――ほとんどの場合は。
欠点は鮮度です。キャッシュは誤ることがあります。
共有ドキュメントをサーバに保存しているとします。ワークステーションは即時に開くためにファイルをキャッシュします。別の同僚が文書を編集・保存すると、キャッシュが気づかないと古い内容を見続け、場合によっては古いコピーを編集して新しい版を上書きしてしまうかもしれません。
したがって、あらゆるキャッシュ設計は以下の間のトレードオフです:\n\n- 性能: ネットワーク往復が減り応答が速くなる\n- 一貫性: 古いデータや驚くべき振る舞いを避ける
チームは通常、次のような手段でトレードオフを管理します:\n\n- TTL(有効期間): キャッシュデータは一定時間後に期限切れになる\n- 無効化: データが変更されたときにキャッシュへ通知してエントリを削除/更新する\n- リース: キャッシュが短い期間だけ「有効」として保持する許可を与え、その後更新を要求する
現代のシステムでは同じパターンが至る所で使われます:CDNはユーザー近傍でウェブコンテンツをキャッシュし、ブラウザやモバイルアプリはアセットやAPIレスポンスをキャッシュし、RedisやMemcachedのようなデータベースキャッシュ層はプライマリストアの負荷を下げます。
繰り返しになりますが、キャッシュは最も安価な性能改善であることが多いが、製品ごとに「十分に新鮮」とは何かを明確にする必要があるという教訓は変わりません。
大規模でのセキュリティは「あなたは誰か?」だけでなく「あなたは今、この特定のリソースで何ができるか?」でもあります。ランプソンとPARCの伝統はここで実用的な考えを押しました:キャパビリティ(capabilities)。
キャパビリティは、ファイル、プリンタ、メールボックス、サービス操作のような何かへのアクセスを許可する改竄不可能なトークンです。トークンを保持していれば許可された操作を行え、持っていなければ行えません。
重要なのは「改竄不可能」であること:システムは有効なトークンを推測で作ることができないようにします。
ホテルの鍵カードが滞在中だけ自分の部屋を開けるのに似ていて、手書きの「OK」と書かれたメモとは異なります。
多くのシステムは、ユーザーとして認証し、リソース側の**ACL(アクセス制御リスト)**で毎回照合するアイデンティティベースのセキュリティに依存します。ACLは直感的ですが分散システムでは扱いにくくなることがあります:\n\n- 各サービスが確実にあなたのアイデンティティを知っている必要がある\n- 各リソースが権限リストを保持・管理する必要がある\n- 「このジョブに10分だけ1ファイルを読む権限を与える」といった委譲が特別扱いのロジックになることが多い
キャパビリティはデフォルトを逆転させます。中央の権威に毎回尋ねる代わりに、トークンを提示すれば権利が既に符号化されているのです。
分散システムは常にマシン間で仕事を渡します:フロントエンドがバックエンドを呼ぶ、スケジューラがワーカーにタスクを渡す、サービスが別のサービスをトリガする。各ホップは「ちょうど十分な」権限を安全に運ぶ方法を必要とします。
キャパビリティはそれを自然にします:トークンを要求と一緒に渡せば受け取り側はそれを検証でき、毎回信頼を再構築する必要がありません。
適切に行えば、過剰権限を減らし、問題発生時の被害範囲を限定できます。
キャパビリティは今日次のように現れます:\n\n- 署名トークン(例: JWT)で特定のクレームを示す\n- スコープ付き資格情報(OAuthアクセストークン、クラウドのセッショントークン)で有効期限・操作範囲を限定する\n- 最小権限のサービスID(ワークロードアイデンティティ、サービスアカウント)で資格情報を狭くする
教訓は明快です:委譲、スコープ、期限を中心にアクセスを設計し、長期的な身元だけで設計しないこと。
分散システムは一斉に「壊れる」わけではありません。混乱し、部分的に壊れます:プロセスが途中で落ちてメモリ上の状態が失われる、スイッチが再起動する、ネットワークがパケットを落とす、ラックの一部だけ停電するなど。
ユーザーから見るとサービスは「稼働中」でも、その一部は到達不可能という状態が起きます。
実用的な障害モデルは率直です:\n\n- プロセスはクラッシュしメモリ内状態を失う\n- マシンは予告なく再起動する\n- ネットワークは分断(グループ間で通信不可)したり遅延や再順序化を起こす\n- 時間は不確実:リクエストは遅いだけで失われていないかもしれない
これを受け入れると、エラーを「端っこのケース」と扱うのではなく通常の制御フローとして扱い始めます。
多くのシステムは少数の手法に頼ります。
タイムアウトは呼び出し元が永遠に待たないようにします。重要なのは実際の遅延データに基づいてタイムアウトを選ぶことです。
再試行は一時的な障害から回復できますが、障害時に負荷を増幅することもあります。だから指数バックオフ(再試行ごとに待ち時間を長くする)とジッタ(ランダム化)が重要で、同期化されたリトライの嵐を防ぎます。
フェイルオーバー(スタンバイインスタンスやレプリカへ切替)は真に落ちたときに有効ですが、検出を安全かつ迅速に行えることが前提です。
再試行すると処理が複数回実行される可能性があります。これはat-least-once配達:仕事を落とさないように頑張るが複製が生じ得る。
exactly-onceは一度だけ実行されることを意味しますが、ネットワーク分断をまたぐと実現は難しい。
多くのチームは代わりに操作をイデンプテントに設計し、at-least-onceで十分に扱えるようにします。
最も信頼性の高いチームはステージング(時に本番)で障害注入を行い何が起きるかを見る:インスタンスを落とす、ネットワーク経路をブロックする、依存を遅くする、アラーム・再試行・ユーザー影響を検証する。
停止を驚きと扱うのではなく、改善のための実験として扱ってください。
OSは年を取るごとに複雑になります:新機能が増えるほど相互作用のパターンは指数的に増え、バグはそこに隠れます。
ランプソン流はOS構造をスケール戦略と見なします。コアが散らかっていればその上に作るものはすべて同じ散らかりを継承します。
PARC時代の繰り返される教訓は、カーネル(あるいは信頼できるコア)は狭く、単純で合成可能なプリミティブで構成することです。多数の特殊ケースを組み込むのではなく、説明しやすく誤用しにくい少数のメカニズムを定義します。
境界が明確であれば(コンポーネントが何を約束し何を仮定できるか)、実装を差し替えたり、部分を孤立してテストしたり、偶発的な結合を避けることができます。
隔離は被害範囲を限定します。メモリ保護、プロセス分離、最小権限でのリソースアクセスなどは「どこかのバグが全部を壊す」を「バグは局所に閉じる」に変えます。
この考えはキャパビリティ的設計へと促します:コードに必要な権限だけを与え、アクセスを明示的にするのです。
実利主義は性能にも現れます:一般的な操作に高速パスを作り、明確さや安全を犠牲にしない余計なオーバーヘッドを避けます。
目的はすべてを微最適化することではなく、通常のケースを即時に感じさせつつ正しさを保つことです。
同じ考えは今日のカーネルや言語ランタイム、コンテナ化プラットフォームに見えます:小さな信頼基盤、明確なAPI、プロセス/サンドボックス/ネームスペースの隔離境界がチームに迅速なデリバリを可能にし、共通の障害モードを共有しないようにします。
詳細は変わりましたが、設計習慣は今も有益です。
PARCの大きな勝利は単一の発明ではなく、実際に人が使えるネットワーク化システムを作る一貫した方法論でした。名前は変わっても基本問題(レイテンシ、障害、信頼、所有権)は変わりません。
設計を見直すときの“精神辞書”:\n\n- RPC → API(REST/gRPC/GraphQL):ワイヤを隠すが、タイムアウト、再試行、イデンプテント性は明示的に。\n- ネーミング & ディレクトリ → DNS + サービスディスカバリ:"どこにあるか" を第一級の懸念にする。\n- キャッシュ → CDN + ローカルキャッシュ + エッジストレージ:速さは簡単、正しさが難しい。\n- キャパビリティ → トークン/キー/スコープ(OAuthスコープ、macaroons、署名付きURL):特定の権利を付与する。\n- サービス、モノリスではなく → 明確な契約を持つモジュラーなシステム:分離は所有とインターフェイスが明確な場合に有効。
評価時に使ってください:\n\n1. サービス境界とオーナーは誰か? 担当チームがないコンポーネントは衰退する。\n2. クライアントはサービスをどう見つけるか? 発見、バージョニング、ロールアウト戦略を早めに定義する。\n3. 障害プランは何か? タイムアウト、再試行、サーキットブレーカー、"劣化モード" を決める。\n4. 状態はどこにありどう保護されるか? 正 authoritative なソース、複製ルール、バックアップ/復元を識別する。\n5. どこをキャッシュし何が古くなってよいか? 一貫性期待を平易な言葉で書く。\n6. 権限モデルは何か? 最小権限のトークンと短命資格情報を好む。\n7. どう観測するか? ログ、メトリクス、トレース、ユーザー体験に結び付いた明確なSLO。
現代の変化の一つはプロトタイプを作る速さです。Koder.aiのようなツール(チャットからWeb、バックエンド、モバイルを生成するvibe-codingプラットフォーム)は、「最初に動くシステム」を高速に作ることを助けます――フロントにReact、バックエンドにGo + PostgreSQL、モバイルにFlutterといったスタックをすぐに出せます。コードのエクスポートと正式なプロダクション進化も可能です。
しかしランプソン時代の教訓は変わりません:速さはインターフェイスを明確にし、障害挙動(タイムアウト、再試行、イデンプテント性)を明示し、ネーミング、キャッシュ、権限を第一級の設計決定として扱うなら勝ちです。
模倣すべきは規律:単純なインターフェイス、明示的な契約、部分障害を前提にした設計。メカニズムは適応する:今日なら管理されたディスカバリ、APIゲートウェイ、クラウドIAMを使うことが多く、手作りのディレクトリや自前認証は避ける方向です。
避けるべきは過度の中央集権化(みんなが依存する単一の「万能サービス」)と不明確な所有(誰も責任を持たない共有コンポーネント)。
ツールは変わり続けますが制約は残ります:ネットワークは壊れる、レイテンシは存在する、人間が操作できるシステムだけが本当の意味でスケールします。
この文脈で「スケール」とは、多くのユーザー、多数のマシン、現実世界のノイズが常に存在する状況での運用を指します。複数サービスにまたがるリクエストや部分的な障害が生じるときに、予測可能に振る舞わせることが難しくなる点が本質です。
PARCは完結した「ネットワーク化された職場」を作り上げました:Altoとイーサネットで接続された個人用コンピュータが、ファイル/プリントサーバのような共有サービスと結びついて日常的に使われたのです。真のシステム問題(ネーミング、過負荷、キャッシュ、障害、セキュリティ)は、エンドツーエンドの実運用を観察しないと見えてきません。
クライアント側で即時応答が求められる操作(UIや編集など)はローカルで行い、共有・権威ある状態はサービス側に置く、という実用的な分割です。目標はローカルの高速応答性と、ネットワークが不安定でも成り立つ一貫したグローバルな振る舞いです。
共有されたネットワークは第一級の依存物になります。多くのマシンが同じ媒体を共有すると、次のことを前提に設計する必要があります:
実務的なデフォルトは、早めの計測、タイムアウトの設定、再試行はバックオフ付きで行うことです。
サービス分割は明瞭さと独立した進化をもたらします:各サービスは焦点の定まった目的と定義済みのインターフェイスを持ちます。代償はネットワーク往復と部分的な障害モードの増加ですから、契約(API)と信頼性(タイムアウト、再試行、ユーザー向けのエラー表現)に関する規律が必要です。
RPCはリモート操作をローカル呼び出しのように見せますが、ネットワークの現実を隠すと誤解を招きます。良いRPCは次を明示します:
これらがないと「ローカルっぽいのでリモートだと忘れる」危険があります。
タイムアウトや応答喪失で再試行が不可避になるため、再試行しても副作用が生じないこと(イデンプテント性)が重要です。設計の実例:chargeCreditCard(orderId, amount)は再試行で二重課金の恐れがあるため安全でない。chargeCreditCard(orderId)のように一意な識別子で重複を検出・無視する仕組みにすることで再試行を安全にできます。
名前がそのまま場所(ホスト/IP/パス)になっていると、移行や障害がユーザー向けの停止になります。安定した名前と変わりうる場所を分離し、ディレクトリや発見システムで「今どこにあるか」を答えられるようにします。クライアントはTTLなどの鮮度ルールでキャッシュします。
キャッシュは最も安価な性能改善ですが、陳腐化のリスクがつきまといます。一般的な手法:
各データが「どの程度の鮮度で十分か」を明文化するのが重要です。
能力(capability)は特定リソースや操作への改竄不可能なトークンです。身元 + ACL方式に比べ、分散系での委譲や最小権限を扱いやすくします。実務的には:
現代の類例はOAuthトークン、署名付きURL、注意深く使うJWTなどです。