今日のゴール
- 名前付きスペースの概念と用途を理解する
- 複数スペースを使ったアプリケーション設計を学ぶ
- スペース間のデータ分離と整理術を身につける
なぜ複数のスペースが必要か
単一のタプルスペースでも多くの問題は解決できます。しかし、アプリケーションが大きくなると問題が発生します。
| 問題 | 名前付きスペースで解決 |
|---|---|
| 名前空間の衝突 | スペースごとに独立 |
| 検索効率の低下 | 関連するタプルだけをスキャン |
| 論理的な分離の欠如 | 責務ごとにスペースを分割 |
基本的な使い方
let manager = newSpaceManager()
# デフォルトスペース
let defaultSpace = manager.space()
# 名前付きスペース
let orders = manager.space("orders")
let inventory = manager.space("inventory")
let logs = manager.space("logs")
# 各スペースは完全に独立
await orders.writeAsync(toTuple(strVal("order"), intVal(1001)))
await logs.writeAsync(toTuple(strVal("log"), strVal("info"), strVal("Started")))
データの分離
異なるスペースのデータは完全に分離されています。
let spaceA = manager.space("A")
let spaceB = manager.space("B")
# 同じ構造のタプルを両方に書き込み
await spaceA.writeAsync(toTuple(strVal("data"), intVal(100)))
await spaceB.writeAsync(toTuple(strVal("data"), intVal(200)))
# それぞれ独立して読み取り
let fromA = await spaceA.readAsync(pattern) # 100
let fromB = await spaceB.readAsync(pattern) # 200
# Aからtakeしても、Bには影響なし
discard await spaceA.takeAsync(pattern)
let stillInB = await spaceB.tryReadAsync(pattern) # Some(200)
設計パターン
パターン1: 機能別分離
let jobs = manager.space("jobs") # ジョブのみ
let results = manager.space("results") # 結果のみ
let config = manager.space("config") # 設定のみ
パターン2: テナント別分離(マルチテナント)
proc getSpaceForTenant(tenantId: string): TupleSpace =
manager.space("tenant_" & tenantId)
let tenantA = getSpaceForTenant("A")
let tenantB = getSpaceForTenant("B")
# 完全にデータが分離される
パターン3: パイプライン(ステージ別)
let input = manager.space("input")
let processing = manager.space("processing")
let output = manager.space("output")
# 各ステージが独立したプロセスで動作
ベストプラクティス
1. 命名規則を決める
# スネークケース + プレフィックス
"job_queue"
"job_results"
"user_sessions"
# または階層的
"app/jobs"
"app/results"
"admin/config"
2. スペースの責務を明確に
# ✅ 単一責務
let jobQueue = manager.space("jobs") # ジョブのみ
let jobResults = manager.space("results") # 結果のみ
# ❌ 複数責務
let everything = manager.space("all") # 何でも入る
3. 定数で管理
const
SPACE_JOBS = "jobs"
SPACE_RESULTS = "results"
SPACE_CONFIG = "config"
proc getJobSpace(manager: SpaceManager): TupleSpace =
manager.space(SPACE_JOBS)
まとめ
学んだこと
| トピック | ポイント |
|---|---|
| 作成と取得 | manager.space("name") |
| データ分離 | スペース間は完全に独立 |
| 設計パターン | 機能別、テナント別、ステージ別 |
| ベストプラクティス | 命名規則、単一責務、定数管理 |
選び方の指針
| 状況 | 推奨 |
|---|---|
| 小規模アプリ | 単一スペース + タイプタグ |
| 機能が明確に分かれる | 機能別スペース |
| マルチテナント | テナント別スペース |
| パイプライン処理 | ステージ別スペース |
演習問題
問題7-1: チャットルーム
複数のチャットルームを名前付きスペースで実装してください。
ヒント
- 各ルームは
manager.space("room_" & roomName)で作成 - メッセージは
("message", userId, text, timestamp)という形式 - ルーム一覧は
manager.spaceNames()で取得可能
問題7-2: キャッシュ層
"primary"と"cache"の2つのスペースを使って、簡単なキャッシュ機構を実装してください。
ヒント
- まず
cacheスペースから検索 - なければ
primaryスペースから取得してcacheに書き込み - TTL(Day 10で学ぶ)を使うとさらに本格的に
問題7-3: ジョブ状態管理
jobs, running, completed の3つのスペースを使って、ジョブの状態管理システムを実装してください。
ヒント
- ジョブ投入:
jobsに書き込み - ワーカー開始:
jobsからtake →runningに書き込み - ワーカー完了:
runningからtake →completedに書き込み - 各スペースの件数で状態を把握