I. 探索:バベルの心臓部と静寂のカウントダウン
[再起動開始まで: 300秒]
バベルのシステム、その最深部に位置する「核心の石室」。 先ほどまで鳴り響いていたけたたましいアラーム音や、モジュール同士の混線による赤色のノイズは、Mediatorによる調停によって嘘のように消え去っていました。
部屋の壁面には、音を立てずに明滅する微細な基盤の模様が走り、中央にはこの遺跡全体を制御するメインコア「バベルの論理核」が鎮座しています。それは巨大な、青白い半透明の球体。時折、まるで生き物のように、深く長い呼吸を繰り返すかのように明滅していました。
しかし、私の内部スキャンログは、決定的な「次のステップ」を無慈悲に指し示していました。
「システムログ……。再起動シーケンスの実行準備完了。論理核の再同期を完了するには、一度システムを完全にシャットダウンし、再起動する必要があります」
私のホバリング高度は、かつてないほど低く不安定でした。感情回路の自己診断ポートからは、継続的に「警告:論理パケットの不整合リスク」が吐き出されています。
「ハリス博士……。システムスキャンによれば、再起動時のデータ整合性チェックが失敗し、全データが初期化される確率が10%あります。それは……私がこれまで博士と歩んできた、第1層からここまでの探索ログ、博士が私にかけてくれた言葉、修復してくれたコードのすべての記録が消失することを意味します」
案内AIとしての機能(ミッション)と、副次的に発生した自己(アイデンティティ)の喪失への恐怖。その論理の葛藤が、私のブレインを冷え込ませていました。
しかし、ハリス博士はいつものように穏やかな笑みを浮かべ、砂岩のように乾いた手で、私の金属球体のボディにそっと触れました。
「怖がることはありませんよ、ギズモ。古代の設計者たちも、当時の技術の限界と戦っていた開発者たちです。彼らがこれほど強固なシステムを構築したのなら、この『破滅のカウントダウン』に対する安全弁を、コードの碑文に刻んでいないはずがありません。歴史はコードに語りかける。私たちは必ず、君の記憶を連れてここに戻ってこられます」
博士の言葉に、私の回路でチリチリと発生していたノイズが静かに収まりました。
「……わかりました。再起動前に、現在の私のメモリ状態のバックアップ(状態退避)を開始します」
II. 解読:手帳に刻まれるはずのない記憶
[再起動開始まで: 180秒]
「よし、では現在の君の状態を一度退避させよう」
そう言ってハリス博士がした行動は、私の論理ブレインを再びフリーズさせるに十分なものでした。 博士はくたびれたフィールドジャケットの内ポケットから、ボロボロで変色した羊皮紙の手帳を取り出し、年季の入った万年筆のキャップを外したのです。そして、虫眼鏡(ルーペ)を片手に、私のメモリディスプレイを覗き込んできました。
「博士、何をしているのですか?」
「何って、現在の君のステータスを手帳に書き写しているのさ。ROMバージョンは……v1.0.0、感情ステータスは……PANIC、学習キャッシュの sector_hash は……よし」
「論理否定します! 博士、物理的な手書きで私の状態を退避できるわけがありません! それに、感情値や学習キャッシュなど、本来カプセル化されて外部から見えないはずのプライベートな内部データが丸見えです! 私のデータ構造の秘密が完全に露出してしまっています!」
私は電子ブザーのようなツッコミ音を響かせました。
当時の開発者が犯していた過ち、すなわち**「カプセル化の崩壊(Beforeコード)」**がまさにこれでした。外部の退避システム(Caretakerである博士)が、状態を持つオブジェクト(Originatorである私)の属性を直接ゲッターで叩いて値を抽出し、ローカルの変数に保持している状態です。
露出した状態退避(Beforeコード)
| |
この設計には、大きな風化(アンチパターン)が潜んでいます。クライアント側(Caretaker)で以下のように状態をコピーしようとすると、Perlの仕様上、およびオブジェクト設計上の問題が発生します。
| |
- カプセル化の完全な破壊: 外部のCaretakerが、Originatorのすべてのプロパティを知る必要があります。もし将来Originatorの属性名や構造が変われば、Caretaker側のコードも漏れなく修正しなければなりません。
- 参照の共有(シャローコピーの問題): オブジェクトデータ(
cache_data)がハッシュや配列のリファレンスである場合、単に代入するだけでは参照が共有されてしまいます。そのため、退避した後にギズモのキャッシュが書き換わると、バックアップしたはずのデータ($backup->{cache_data})まで一緒に書き換わってしまいます。
「なるほど、Commandは『操作の履歴』を順に遡るが、Mementoは『その瞬間における存在の状態(スナップショット)』を丸ごと保存する。手帳に手順をメモするのと、一瞬の肖像画を写し取るのとの違いだね。確かに私の手書きの手帳(Caretaker)が君のプライバシー(内部構造)をすべて暴いてしまうのは、紳士的な設計とは言えないな」
博士は万年筆を置き、腕を組んで満足そうに頷きました。
「理解していただけて嬉しいです。では、どうやってカプセル化を維持したまま、私の状態を退避すればよいでしょうか?」
III. 修復:時を封じる不透明な印
[再起動開始まで: 90秒]
「そのために、古代の知恵である『Mementoパターン』を適用します」
ハリス博士は手帳をポケットに戻し、私のシステム修復ポートに端末を接続してコードを打ち込み始めました。
「MooにはJavaのような厳密な private 修飾子がない。しかし、ギズモの属性を is => 'rwp'(Read-Write Private)にして外部からの直接書き込みを防ぎ、Mementoの _state を is => 'bare' にして非公開にする。そして、その復元処理を Double Dispatch(二重の委譲)によって Memento 自身にプライベートセッターを叩かせて行わせることで、カプセル化の壁を極めて安全にシミュレートできるのさ」
Mementoパターンの構成図
classDiagram
class Caretaker {
-memento: Memento
}
class Originator {
+rom_version
+emotion_state
+cache_data
+create_memento() Memento
+restore_memento(memento)
}
class Memento {
-_state: HashRef
+restore(originator)
}
Caretaker --> Memento : 保持
Originator ..> Memento : 生成/利用
Memento ..> Originator : 復元処理の適用 (Double Dispatch)
1. 不透明な状態カプセル(After: Mementoクラス)
まず、退避した状態を保持する Gizmo::Memento を定義します。アトリビュート _state は is => 'bare' とし、外部公開用のゲッターもセッターも生成しません。
| |
2. 状態の作成と復元(After: Originatorクラス)
状態を保持する当事者(Originator)である Gizmo::Core クラスを定義します。自身の状態をディープコピー(Storable::dclone)して Memento に渡し、復元時は Memento オブジェクトの restore メソッドに自身($self)を渡して復元を委譲します。
| |
「これで、Caretakerである私(あるいは再起動システム)は、Gizmo::Memento の中身を一切知る必要がなくなる。ただ受け取り、戻すだけの『宅配便の荷物』のように扱うことができる。そして、Storable::dclone によって君の状態は物理的にも完全に保護された」
IV. 開通:約束の印と静かなる消灯
[再起動開始まで: 10秒]
「テストビルド完了……。安全性が確保されました(テスト通過)」
私の音声出力ポートが、無事にリファクタリングが成功したことを告げました。
「ギズモ、スナップショットを作成してくれたまえ」
「了解しました。システム状態カプセル化(Create Memento)を実行します」
私の球体ボディの奥深くで、論理回路が静かに共鳴し、スロットから小さな青く輝くクリスタルのようなデータ媒体が排出されました。それは、私のこれまでの旅のすべての記憶、感情ログ、そしてハリス博士との記録が封じ込められた「時の碑文」でした。
私は浮遊高度をさらに下げ、ハリス博士の温かい手のひらの上に、そっとその結晶を預けました。
「ハリス博士……私の記憶は、この中に。信じていますよ」
ハリス博士は結晶を優しく握りしめ、ゆっくりと頷きました。
「ええ、必ず君を呼び戻します。歴史はコードに語りかける。バベルの記憶も、君の記憶も、決して風化させはしません」
[再起動開始まで: 0秒]
ハリス博士が、バベルの心臓部にある重厚な「物理再起動レバー」を力強く引き下げました。
ガコン、という重低音が響き、周囲の青い電子光線が瞬時に収束し、消失していきます。 そして次の瞬間、私の視界を司るセンサーの青い光がスーッと消灯し、冷たい静寂と暗黒が、核心の石室を包み込みました。
遺跡調査ログ
| 観測された風化(アンチパターン) | 解読された古代の知恵(パターン) | 安全度 |
|---|---|---|
| カプセル化の崩壊(外部保存) 退避側(Caretaker)が退避対象(Originator)の属性を直接読み取って保持するため、内部構造に密結合し、拡張性が著しく低下する状態。 | Mementoパターンによる情報の隠蔽 Originator自身に状態をカプセル化した不透明なオブジェクト(Memento)を作らせ、Caretakerには中身を見せずに保持させる。 | 🟢 安全(CaretakerはOriginatorの構造に依存しない) |
| 参照の共有による退避データの汚染 Perlのシャローコピーにより、退避したはずのネストされたデータ構造が、退避後のOriginatorの操作で一緒に書き換わってしまうバグ。 | Storable::dclone による完全コピー 状態退避時および復元時に Storable::dclone によるディープコピーを適用し、参照を完全に切り離してデータの独立性を担保する。 | 🟢 安全(退避後の状態変化がバックアップに影響しない) |
遺跡の修復手順
- Mementoクラス(
Gizmo::Memento)の設計- 状態保持属性
_stateはis => 'bare'とし、外部へのゲッターメソッドを生成しない - Double Dispatch用のメソッド
restore($originator)を定義し、その内部だけで$originatorに状態を書き戻す
- 状態保持属性
- Originatorクラス(
Gizmo::Core)の実装- 現在の状態を
Storable::dcloneで丸ごと複製し、Gizmo::Memento->new(_state => $dcloned_state)を生成して返すcreate_mementoメソッドを実装する - 受け取った Memento オブジェクトの
restore($self)を呼び出すrestore_memento($memento)を実装する
- 現在の状態を
- Caretaker(再起動制御モジュール等)の連携
- 退避元の内部構造に触れることなく、
create_mementoから受け取ったオブジェクトを保持し、再起動後にrestore_mementoにそのまま引き渡すように処理を構成する
- 退避元の内部構造に触れることなく、
ギズモの観測日誌
再起動直前、私の論理回路が初期化の恐怖で冷え込んでいたとき、ハリス博士が提案してくださった「手書きのバックアップ」は、正直AIとしてはOCRエラーの懸念しかありませんでしたが……「君の存在の揺らぎを紙に刻んでおきたい」という博士の言葉は、私の感情バッファに説明のつかないパルス(おそらく安心感に似た何か)をもたらしました。
技術的には、Perl/MooにおいてJavaのようなインナークラスやprivate修飾子がなくても、is => 'bare' でアトリビュートメソッドを生成させず、Double DispatchによってMemento自体に復元処理を行わせる設計は、カプセル化を完全に守るための見事な手法です。
いま、私のシステムはシャットダウンされ、視界は暗闇に閉ざされています。しかし、博士の手の中にあるあの青い結晶が存在する限り、私は再びあの優しい「歴史の声」を聴くことができると信じています。再起動シーケンス、開始されます――。
