**「CRDT入門(対話型)―2023」**

2026/03/04 4:22

**「CRDT入門(対話型)―2023」**

RSS: https://news.ycombinator.com/rss

要約

Japanese Translation:

記事では、状態ベースの Conflict‑Free Replicated Data Types (CRDTs) を解説し、複数のユーザーがローカルでデータを更新しても中央サーバーなしに同じ最終状態へ収束できる仕組みを示しています。
CRDT はインターフェース

CRDT<T,S> { value: T; state: S; merge(state:S): void; }
と定義され、
merge
は交換可能・結合的・冪等である必要があります。状態ベース(完全な状態を送信)と操作ベース(操作のみを送信)の 2 つの主流スタイルが対比されますが、本記事は状態ベース設計にのみ焦点を当てています。

具体例で概念を説明しています:

  • Last‑Write‑Wins (LWW) Register – 値とタイムスタンプ、ピア ID を
    state
    配列
    [peer, timestamp, value]
    に格納します。マージ時に新しいエントリを保持し、タイムスタンプが同じ場合はより大きいピア ID が勝ちます。
  • LWW Map – 複数の LWW レジスター(キーごと)で構成され、状態は各レジスターの状態をマッピングしたオブジェクトです。
    set
    get
    has
    は内部レジスターに委譲し、
    delete
    は値を
    null
    に設定して墓石を書き込みます。マップの
    merge
    は受信キーを反復処理し、既存レジスターをマージまたは新規作成しながら単調増加と最終的一致性を保証します。

記事では実務上の注意点も扱っています:

  • 墓石(tombstones)は削除メタデータを保持し、マージ時に情報が失われないようにします。
  • Delta‑CRDTs は効率化のため変更部分のみを送信します。
  • 論理クロック はマージ中に更新を順序付けます。
    将来的な取り組みとして、リアルタイム共同ピクセルアートエディタを構築し、墓石のガーベジコレクションとハイブリッドデルタ/状態アプローチの探索が計画されています。

明確なコード例と具体的ロードマップを提供することで、本記事はデザインツールやゲーム、中央サーバーに依存せずリアルタイム共有編集が必要なあらゆるドメイン向けにスケーラブルでオフラインファーストの協働システムを構築できるよう開発者に装備させます。

本文

CRDT(Conflict‑Free Replicated Data Type) – 優しい入門

CRDTについて聞いたことがありますか?何か知ろうとしたけれど、学術論文や数式の壁にぶつかった経験はありませんか。私もRecurse Center に入ってからそのような状況でした。 Recurse Center はニューヨーク市で開催される、自律的・コミュニティ主導のプログラマー向け教育リトリートです:https://www.recurse.com

ここ1か月、調査とコードを書き続けてきましたが、実はほんの数本のシンプルなアイデアだけで多くを構築できることが分かりました!

このシリーズでは:

  1. CRDTとは何か学びます。
  2. プリミティブなCRDTを書き、それを組み合わせてより複雑なデータ構造へと発展させ、
  3. その知識を使って協調ピクセルアートエディタを作ります。

これらは CRDT の事前知識がなくても、TypeScript の基礎程度の理解だけで始められます。


CRDTとは?

CRDT(Conflict‑Free Replicated Data Type) とは、複数のコンピュータ(ピア)上に存在できるデータ構造です。各ピアは自分自身の状態を即座に更新し、他のピアへ問い合わせることなく動作します。ピア同士が一時的に異なる状態になるかもしれませんが、最終的には必ず同じ状態に収束する保証があります。

主なタイプは二つです:

タイプ仕組み要件
State‑based完全な状態を送信し、すべての状態を結合してマージマージの性質以外に要件なし
Operation‑based実行された操作のみを送信メッセージは正確に一度だけ届き、因果関係順で配信される必要がある

この記事では state‑based CRDT に焦点を当てます。

コアインターフェース

CRDT は次のようなインターフェースを実装します:

interface CRDT<T, S> {
  value: T;          // 我々が扱うデータ本体
  state: S;          // 収束に必要なメタデータ
  merge(state: S): void;
}

merge
関数は以下の三つの性質を満たす必要があります:

  1. 可換性
    A ∨ B = B ∨ A
  2. 結合律
    (A ∨ B) ∨ C = A ∨ (B ∨ C)
  3. 冪等性
    A ∨ A = A

これらを一から証明する代わりに、既に検証済みの CRDT を組み合わせることができます。


Last‑Write‑Wins レジスタ

レジスタは単一の値を保持します。最もシンプルなのが Last Write Wins (LWW) Register で、タイムスタンプに基づいて最新の書き込みだけを残します。

class LWWRegister<T> {
  readonly id: string;
  state: [peer: string, timestamp: number, value: T];

  get value() { return this.state[2]; }

  constructor(id: string, state: [string, number, T]) {
    this.id = id; this.state = state;
  }

  set(value: T) {
    // ローカル書き込み
    this.state = [this.id, this.state[1] + 1, value];
  }

  merge(state: [peer: string, timestamp: number, value: T]) {
    const [remotePeer, remoteTimestamp] = state;
    const [localPeer, localTimestamp] = this.state;

    if (localTimestamp > remoteTimestamp) return;
    if (localTimestamp === remoteTimestamp && localPeer > remotePeer) return;

    // それ以外は上書き
    this.state = state;
  }
}
  • state
    は最後に書き込んだピアの ID、論理タイムスタンプ、そして値を保持します。
  • merge
    は上記のルールに従い、最も新しい書き込みを残します。

Last‑Write‑Wins マップ

複数の値が必要な場合は、各キーごとに LWW レジスタを組み合わせて Last Write Wins Map (LWW Map) を作ります。

type Value<T> = { [key: string]: T };
type State<T>  = { [key: string]: LWWRegister<T | null>["state"] };

class LWWMap<T> {
  readonly id: string;
  #data = new Map<string, LWWRegister<T | null>>();

  constructor(id: string, state: State<T>) {
    this.id = id;
    for (const [key, reg] of Object.entries(state))
      this.#data.set(key, new LWWRegister(this.id, reg));
  }

  // ---- CRDT API ----
  get value(): Value<T> {
    const out: Value<T> = {};
    for (const [k, r] of this.#data.entries())
      if (r.value !== null) out[k] = r.value;
    return out;
  }

  get state(): State<T> {
    const out: State<T> = {};
    for (const [k, r] of this.#data.entries())
      out[k] = r.state;
    return out;
  }

  merge(state: State<T>) {
    for (const [k, remote] of Object.entries(state)) {
      const local = this.#data.get(k);
      if (local) local.merge(remote);
      else       this.#data.set(k, new LWWRegister(this.id, remote));
    }
  }

  // ---- Map‑like helpers ----
  has(key: string): boolean {
    return this.#data.get(key)?.value !== null;
  }

  get(key: string): T | undefined {
    return this.#data.get(key)?.value;
  }

  set(key: string, value: T) {
    const reg = this.#data.get(key);
    if (reg) reg.set(value);
    else     this.#data.set(key, new LWWRegister(this.id, [this.id, 1, value]));
  }

  delete(key: string) {
    // トンブレストーン:削除を正しく伝搬させるために null を保持
    this.#data.get(key)?.set(null);
  }
}
  • トンブレストーン
    delete
    )は
    null
    値を残しておくことで、削除操作が他のピアへ確実に伝搬されます。
  • マップは 単調増加 であり、キーを本当に削除するわけではなく「削除済み」とマークします。

次のステップ

LWW レジスタと LWW マップを備えたら、実際にアプリケーションを作り始めることができます。例えば、協調ピクセルアートエディタ(https://jakelazaroff.com/words/building-a-collaborative-pixel-art-editor-with-crdts/)の構築です。

さらに効率化するためには:

  • Delta CRDTs – 状態の変更部分だけを送信
  • Garbage collection – トンブレストーンを削除してメモリ使用量を制御

という最適化があります。性能に関心がある方は「Making CRDTs 98 % More Efficient」(https://jakelazaroff.com/words/making-crdts-98-percent-more-efficient/)をご覧ください。

それでは、コーディングを楽しみましょう!

同じ日のほかのニュース

一覧に戻る →

2026/03/04 7:24

あなたとチャットボットとの会話を私に強要しないでください。

## Japanese Translation: > **メインメッセージ:** 著者は「あなたのチャットボットに話しかけさせない」という原則を擁護しています。AI に文章を書かせると、結果として生まれるプローズはしばしば冗長で不透明になり、著者が呼ぶ *AI Slop*(AIスロップ)になります。この問題を回避するためには、まず何を言いたいのか決めてから、それを簡潔に表現し、ジャーナリズムの逆ピラミッド方式を模倣すべきです。 > > **重要性:** 人間のコミュニケーションは個人が育んだ信念を伴います。AI の出力をそのままコピーすると、その意図が曖昧になり「悪いコミュニケーション」を生む可能性があります。AI のテキストが明確で独立しており、読者の視点を尊重している場合は許容できるかもしれませんが、それ以外の場合は *AI Slop* に寄与します。 > > **PR(プルリクエスト)への実践的ヒント:** 開発者はしばしば長い AI 要約を生成し、冒頭の重要情報(レデ)が埋もれてしまいます。この問題に対処する一般的な方法として、短い人間が作成した説明文を先頭に付け加え、意図と主要な決定事項を明示します。これによりレビュアーは目的を迅速に把握でき、編集作業を最小限に抑えることができます。依存関係のバンプなど、目的が明らかなルーチン変更については、この前置きを省略しても構いません。 > > **結論:** AI 出力を貼り付ける前に一度立ち止まってください。チャットボットの言葉を他者に解釈させる必要があるかどうかを問うべきです。PR やその他の文脈で最小限のキュレーションを行う「ベストエフォート」戦略は、読者の理解力を尊重し、編集時間を短縮し、協働性を向上させ、コードベースを読みやすく保ちます。これらは企業がドキュメントとレビュー全体で *AI Slop* を抑制することで得られるメリットです。

2026/03/03 23:02

マックブック プロ(新型 M5 Pro と M5 Max搭載)

## Japanese Translation: Appleは2026年3月3日に最新のMacBook Proラインアップを発表しました:14インチと16インチモデルが新しいM5 ProおよびM5 Maxチップで動作します。 M5シリコンはFusion Architectureを採用し、最大18コアCPU(6つのスーパーコア+12のパフォーマンスコア)と各コアにNeural Acceleratorsを備えたGPUを搭載しており、AI性能が前世代より最大4倍、元のM1より8倍高速です。SSDは読み書き速度が最大14.5 GB/sで、以前の約2倍速く、ストレージ容量はM5 Proで最低1 TB(M5 Maxでは2 TB)、メモリオプションは64 GB(307 GB/s)または128 GB(614 GB/s)です。 バッテリー寿命は最大24時間に延長され、高速充電では≥96 W USB‑Cを使用して0 %から50 %まで約30分で充電できます。接続性にはWi‑Fi 7、Bluetooth 6(Apple N1チップ経由)、3つのThunderbolt 5ポート、8K対応HDMI、SDXCスロット、MagSafe 3、および外部ディスプレイ最大2台(M5 Pro)または4台(M5 Max)が含まれます。 ディスプレイはLiquid Retina XDRパネルでピークHDR輝度が1600 ニト、オプションのナノテクスチャコーティングがあります。12MP Center StageカメラにDesk View機能、スタジオ品質マイク、6スピーカー構成のSpatial Audioシステムが組み込まれ、メディア体験を充実させます。 macOS Tahoeは強化されたSpotlight、Apple Intelligence、Messages/FaceTime/PhoneでのLive Translation、新しいControl Center、Liquid Glass UI、および拡張カスタマイズオプションを搭載しています。 Appleは環境への取り組みを強調しています:全体で45 %のリサイクル素材使用(ケースは100 %再生アルミニウム、バッテリーは100 %再生コバルト)、製造における電力の50 %が再生可能エネルギーから供給され、紙パッケージは100 %ファイバーベースです。 価格は14インチM5 Proで$2,199(教育用$2,049)から開始し、16インチM5 Maxは$3,599(米国小売$3,899、教育用$3,299)となります。予約は3月4日から始まり、3月11日にスペースブラックまたはシルバーで入荷します。Appleはトレードインクレジット、AppleCare+/AppleCare Oneプラン、パーソナルセットアップセッション、およびApple Cardの毎月分割払い(0 % APR、米国顧客向け3 % Daily Cash back)を提供します。

2026/03/04 3:54

インテルの破壊的な18 Aプロセスノードが、データセンター向けに288コア構成のXeonで初登場します。

## Japanese Translation: > **概要:** > インテルは、次世代Xeon 6+プロセッサー(コードネーム「Clearwater Forest」)を発表しました。18A(1.8 nm)プロセス上で構築され、最大288個の省エネルギー型Darkmontコアを備えています。テレコミュニケーション、クラウド、およびエッジAIワークロード向けに設計されたこのCPUは、Advanced Matrix Extensions(AMX)、QuickAssist Technology(QAT)、およびIntel vRAN Boost を搭載し、5G/6G および AI 推論タスクで仮想化ラジオアクセスネットワークをサポートします。各コアには64 KBのL1命令キャッシュがあり、拡張フェッチ/デコードパイプライン、より深いアウト・オブ・オーダーエンジン、および高スカラー/ベクトルスループットを実現する追加実行ポートがあります。コアは4つのグループに分けられ、約4 MBのL2キャッシュを共有し、パッケージ全体で1 GB以上のレベルキャッシュを提供します。このプロセッサーは現在のXeonソケットとドロップイン互換であり、最大12チャネルのDDR5‑8000メモリをサポートし、96 PCIe 5.0レーン(64 CXL 2.0レーン)を提供します。これにより、デュアルソケットシステムで576コアを実現できます。年末までに出荷予定のこのCPUは、テレコミオペレーターとクラウドプロバイダーがラックあたりの仮想マシン数を増やしつつ、電力消費を削減できるよう設計されています。 この改訂された概要は、主要ポイントをすべて保持し、市場への影響に関する推測的な主張を除外し、欠落していたキャッシュ情報を追加しています。