Closed7
100日チャレンジ day39 (Copy On Write シュミレータ)

昨日
100日チャレンジに感化されたので、アレンジして自分でもやってみます。
やりたいこと
- 世の中のさまざまなドメインの簡易実装をつくり、バックエンドの実装に慣れる(dbスキーマ設計や、関数の分割、使いやすいインターフェイスの切り方に慣れる
- 設計力(これはシステムのオーバービューを先に自分で作ってaiに依頼できるようにする
- 生成aiをつかったバイブコーティングになれる
- 実際にやったことはzennのスクラップにまとめ、成果はzennのブログにまとめる(アプリ自体の公開は必須ではないかコードはgithubにおく)
できたもの

バックアップ、スナップショット、Copy on Write を学べるようにする

承知いたしました。「Day39 - インタラクティブCoWストレージシミュレーター」のプロジェクトを開始します。
まずは、このアプリケーションの具体的な作業手順、ディレクトリレイアウト、作成するファイル一覧を以下に提案します。
プロジェクト名
day39_interactive_cow_simulator
デザインテーマ
ミニマリズムとデータビジュアライゼーションの融合
作業手順
-
プロジェクト初期化 (Step 1)
-
template
ディレクトリをコピーしてday39_interactive_cow_simulator
を作成。 -
package.json
のname
をday39_interactive_cow_simulator
に変更。 -
README.md
の初期化(アプリ概要、目的、主な機能)。 - 基本的なレイアウト (
app/layout.tsx
,app/page.tsx
) を作成。Tailwind CSS の設定。 - コミット:
day39: step 1/8 project initialization
-
-
データモデリングとDB設定 (Step 2)
- このアプリケーションは主にフロントエンドでのシミュレーションが中心となるため、サーバーサイドのDBは最小限にします。スナップショットのメタ情報(名前、作成日時など)や、もし永続化したい設定があればそれを保存する程度とします。
-
lib/db.ts
:-
Snapshot
テーブル:id
,name
,createdAt
,diskStateJson
(ディスク状態をJSONで保存)
-
-
db/dev.db
を削除してスキーマを反映。 - コミット:
day39: step 2/8 data modeling and db setup
-
コアロジックと状態管理の実装 (Step 3)
-
app/_lib/cow-simulator.ts
:- 仮想ディスク、ブロック、ファイルのデータ構造定義。
- ファイル作成、変更、削除ロジック(CoWを意識)。
- スナップショット作成ロジック(CoW)。
- ブロックの割り当て、共有状態管理ロジック。
-
app/(pages)/simulator/store.ts
(またはapp/(pages)/simulator/useCowStore.ts
):- Zustand や React Context + useReducer を用いたクライアントサイドの状態管理。
- 仮想ディスクの状態、ファイルリスト、スナップショットリスト、現在の操作などを管理。
- 上記
cow-simulator.ts
のロジックを呼び出すアクションを定義。
- コミット:
day39: step 3/8 core logic and state management implementation
-
-
APIエンドポイント実装 (Step 4)
- (オプション)もしスナップショット情報をサーバーに保存・ロードする機能を作る場合。
-
app/api/snapshots/route.ts
:-
GET
: 保存されたスナップショットの一覧を取得。 -
POST
: 現在のディスク状態からスナップショットを作成しDBに保存。
-
-
app/api/snapshots/[id]/route.ts
:-
GET
: 特定のスナップショット情報を取得。 -
DELETE
: 特定のスナップショットを削除。
-
-
curl
などで API の動作確認。 - コミット:
day39: step 4/8 api endpoint implementation (if any)
-
UIコンポーネント実装 (Step 5)
-
app/(pages)/simulator/page.tsx
: シミュレーター全体のメインページ。 -
app/(pages)/simulator/components/VirtualDiskView.tsx
:- 仮想ディスクのブロックを視覚的に表示(SVGやdiv要素のグリッド)。
- ブロックの色やラベルで状態(未使用、ファイルA、共有など)を表現。
- ブロックへのマウスオーバーで詳細情報を表示するなどのインタラクション。
-
app/(pages)/simulator/components/FileControls.tsx
:- ファイル作成、編集、削除を行うためのUI(入力フォーム、ボタン)。
-
app/(pages)/simulator/components/SnapshotControls.tsx
:- スナップショット作成ボタン、スナップショットリスト表示。
- スナップショット選択で過去の状態を
VirtualDiskView
に反映。
-
app/(pages)/simulator/components/SnapshotTreeView.tsx
(またはSnapshotTimelineView.tsx
):- スナップショット間の関係性を視覚的に表示。
-
app/(pages)/simulator/components/InfoPanel.tsx
:- 現在のストレージ使用量 (論理/物理)、CoWイベントのログなどを表示。
- アプリのタイトルを
Day39 - インタラクティブCoWストレージシミュレーター
とする。 - コミット:
day39: step 5/8 ui component implementation
-
-
主要業務フロー実装 (Step 6)
- ファイル作成 → ブロック割り当て →
VirtualDiskView
更新。 - ファイル編集 → CoW発生 → 新規ブロック割り当て、旧ブロック状態保持 →
VirtualDiskView
更新。 - スナップショット作成 → メタデータ更新、ブロック状態更新 (共有など) →
VirtualDiskView
およびSnapshotTreeView
更新。 - スナップショット選択 →
VirtualDiskView
が選択されたスナップショットの状態を反映。 - コミット:
day39: step 6/8 main business flow implementation
- ファイル作成 → ブロック割り当て →
-
デバッグとテスト (Step 7)
- Playwright を用いたインタラクションのテスト:
- ファイルを作成し、ブロックが正しく割り当てられることを確認。
- ファイルを編集し、CoWが視覚的に正しく表現されることを確認。
- スナップショットを作成し、共有ブロックと新規ブロックが正しく色分けされることを確認。
- 過去のスナップショットを選択し、状態が復元されることを確認。
- 不要なファイルやコードを削除。
- コミット:
day39: step 7/8 debugging and testing
- Playwright を用いたインタラクションのテスト:
-
ドキュメント作成 (Step 8)
-
README.md
の更新 (スクリーンショット、使い方、学んだこと)。 -
.cursor/rules/knowledge.mdc
に今回のアプリ情報を追記。 - コミット:
day39: step 8/8 documentation
-
ディレクトリレイアウト (抜粋)
day39_interactive_cow_simulator/
├── app/
│ ├── api/
│ │ └── snapshots/
│ │ ├── [id]/
│ │ │ └── route.ts
│ │ └── route.ts
│ ├── (pages)/
│ │ └── simulator/
│ │ ├── components/
│ │ │ ├── VirtualDiskView.tsx
│ │ │ ├── FileControls.tsx
│ │ │ ├── SnapshotControls.tsx
│ │ │ ├── SnapshotTreeView.tsx
│ │ │ └── InfoPanel.tsx
│ │ ├── store.ts // Zustand store
│ │ └── page.tsx
│ ├── _lib/
│ │ └── cow-simulator.ts
│ ├── layout.tsx
│ ├── globals.css
│ └── page.tsx
├── components/
│ └── ui/
├── lib/
│ └── db.ts
├── db/
│ └── dev.db
├── public/
├── package.json
├── README.md
└── ... (その他設定ファイル)
作成する主なファイルと行数目安
-
app/_lib/cow-simulator.ts
: (コアロジック) ~200-300行 -
app/(pages)/simulator/store.ts
: (状態管理) ~150-250行 -
app/(pages)/simulator/page.tsx
: (メインページ) ~100行 -
app/(pages)/simulator/components/VirtualDiskView.tsx
: (最重要UI) ~200-300行 -
app/(pages)/simulator/components/FileControls.tsx
: ~80行 -
app/(pages)/simulator/components/SnapshotControls.tsx
: ~100行 -
app/(pages)/simulator/components/SnapshotTreeView.tsx
: ~100行 -
app/(pages)/simulator/components/InfoPanel.tsx
: ~80行 -
lib/db.ts
: ~50行 -
app/api/snapshots/route.ts
: ~80行 -
app/api/snapshots/[id]/route.ts
: ~60行
各ファイルは300行以内を目指し、複雑なコンポーネントは適宜分割します。
SVGやCanvasを直接使う場合、VirtualDiskView.tsx
が少し大きくなる可能性がありますが、その場合は内部コンポーネントに分割することを検討します。React Flowのようなライブラリを使う場合は、その設定やノード定義で多少行数が増えるかもしれません。

一気にここまでできたすごい

これで完成

学び
- cow & snapshot はある時点のデータを残しておき変更の差分のみを保存する
- snapshot を取ることで元データにロックがかかるため、削除したとしても物理的には削除されない
- snapshot を使って戻す場合、snapshot 作成後に作成されたファイルは残り続けるが参照は存在しないのでいずれ消されるっぽい
このスクラップは4ヶ月前にクローズされました