Featured image of post コード考古学者【Proxy】強電磁場の記憶碑〜回路を護る防護の身代わり〜

コード考古学者【Proxy】強電磁場の記憶碑〜回路を護る防護の身代わり〜

強電磁場を放つ古代の記憶石碑から安全かつ効率的にデータを取得するため、アクセス制限と遅延ロード・キャッシュを備えたProxyパターンを導入したコード考古学者の探索記録。

進入

隔壁ゲートの重々しい駆動音が静まり返った後、私たちの目の前に現れたのは、デジタル古代遺跡「バベルのシステム」の中層、その最終節となる第12層『絡み合う暗路』の最奥部でした。

冷え切った暗闇の空間の中央に、青白い放電火花を不規則に散らし、周囲の空気を震わせる巨大な黒い石碑が鎮座していました。これこそが、かつての遺跡の運用ログを蓄積した「古代の記憶石碑(ストレージ)」です。しかし、そこから放射される強力な電磁波と重低音のハミングは、直感的に尋常ではない危険を告げていました。

私は、ログデータをスキャンしようと少しだけ記憶石碑に接近しました。 その瞬間、「バチバチッ!」と私のホバリングセンサーに強烈なスパークが走り、視界のディスプレイがノイズで激しく歪みました。

「システム警告!磁気アラート発令!メモリ揮発危険度レベル・レッド!これ以上近づけば、私の電子頭脳の記録領域が完全に消去され、ただの空き缶に逆戻りしてしまいます!」

私は慌てて後退し、石碑から最も離れた安全な配管の影へと避難しました。 そして、離れた場所から空中プロジェクターを起動し、本尊へ直接接続して読み込みを行おうとする危険なBeforeコードを目の前の壁に投影しました。

1
2
3
4
5
6
7
8
# lib/StorageInterface.pm
package StorageInterface;
use Moo::Role;
use v5.36;

requires 'get_record';

1;
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# lib/RealStorage.pm
package RealStorage;
use Moo;
use v5.36;

with 'StorageInterface';

has connection_established => ( is => 'rw', default => 0 );
has clearance => ( is => 'ro', default => 10 );

sub establish_connection ($self) {
    # 電磁コアへの直接接続。接続者のセーフティレベルが不十分だと焼き切れるトラップが発動する
    if ($self->clearance < 5) {
        die "Hardware Error: Client circuit burnt by strong magnetic field from RealStorage!";
    }
    $self->connection_established(1);
}

sub get_record ($self, $key) {
    if (!$self->connection_established) {
        $self->establish_connection;
    }
    return "DECODED_DATA_FOR_$key";
}

1;
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
# lib/StorageClient.pm
package StorageClient;
use Moo;
use v5.36;
use Types::Standard qw(ConsumerOf);

# インターフェース(ロール)を保持し、透過的な差し替えを可能にする設計
has storage => (
    is       => 'ro',
    isa      => ConsumerOf['StorageInterface'],
    required => 1,
);

sub read_data ($self, $key) {
    # クライアントは相手が誰かを意識せず透過的に呼び出す
    my $data1 = $self->storage->get_record($key);
    my $data2 = $self->storage->get_record($key);
    return [$data1, $data2];
}

1;

碑文解読

「ふむ、触れる者すべてから記憶を奪い去る、美しい『忘却の護符』ですか。当時の開発者が不審なアクセスを排除するために施した、実に徹底した防衛策ですね」

ハリス博士は分厚い絶縁手袋をはめながら、遠巻きに青白い火花を観察して感嘆の声を漏らしました。

私はメモリ揮発の恐怖から、機体をガタガタと小刻みに震わせ、警告アラート音を「ピピピピ……」と鳴らし続けました。

「おやギズモ。古代の素晴らしい技術を前にして、君の演算コアも歓喜で武者震いしているようだね。実に微笑ましい歓迎の舞いだ」 博士は満足そうに頷きました。

「歓喜の武者震いではありません! 死の恐怖です! 物理的に記憶石碑に近寄れない以上、私の力ではログを取得することなど不可能です! 諦めて引き返しましょう!」

「いや、諦める必要はありませんよ。ここには当時の開発者の強い意志が眠っています。彼らとて、すべてのアクセスを拒絶したかったわけではない。適切な資格を持った者に、安全にデータを渡す『身代わり』を用意していたはずです」

「身代わり……ですか?」

「そう、デザインパターンで言う『Proxy(プロキシ)』だよ。今回のように、本尊オブジェクト(RealStorage)への直接アクセスが危険、あるいは処理が極めて重い場合、その本尊と『全く同じインターフェース』を満たす代理オブジェクト(身代わり)を間に挟むのだ」

私はプロジェクターの図面を見つめながら、疑問を投げかけました。 「しかし博士、安全な別のクラスを作って、それを呼び分ければいいのではないですか?」

「それでは、呼び出し側(StorageClient)が『本尊の都合』や『身代わりの都合』をすべて知らねばならなくなり、責任が漏洩してしまう。大事なのは、クライアント側のコードを一切書き換えず、オブジェクトを差し替えるだけでセキュリティやキャッシュを追加できる『透過性(Transparency)』なのだよ」

「透過性……」

「そうだ。クライアントが求めているのは『情報を差し出す相手(インターフェース)』であって、『その相手の具体的な名前(RealStorage)』ではない。双方が同じ StorageInterface ロールを消費していれば、クライアントは相手が本尊か代理人かを意識せずに済むのだ」


遺跡修復

ハリス博士は、安全な配管の陰に隠れている私に向かって、羊皮紙の手帳を掲げました。

「ギズモ、手帳に描いたこの設計図を見てごらん。本尊である電磁ストレージの手前に、我々の身代わりとなる『防護の盾』を配置するのだ」

私はカメラアイの倍率を上げ、手帳の羊皮紙に万年筆で丁寧に引かれたインクのグリッド線をスキャンしました。そこには、共通の役割を通じて本尊を覆い隠す StorageProxy のクラス関係図が描かれていました。

Proxyパターンのクラス図: クライアントがStorageInterfaceを介してStorageProxyおよびRealStorageとやり取りし、遅延ロード、アクセス制限、キャッシュを実現する構造

「なるほど……! StorageClient は相手が誰であるかを知らず、ただ StorageInterface を通じてデータを要求する。そして代理人である StorageProxy が、本尊である RealStorage の代わりにその要求を受け止める構造ですね」

「その通り。この設計ならば、クライアント側のコードを一切書き換えることなく、アクセス制限、遅延ロード、キャッシュという3つの防護壁を透過的に割り込ませることができるのだ」

「本当に見事な盾です! これなら、危険な電磁コアに直接触れることなく、安全にログをサルベージできますね!」

「そうとも。では、この設計図をコードに落とし込もう。ギズモ、君は安全なその場所から遠隔でコーディングを行い、この中継端末に流し込んでくれたまえ。私が磁気手袋を使って、本尊の手前のポートへ物理接続する」

「了解しました! 博士、指示をお願いします!」

博士が火花を散らす石碑の手前で物理ポートを操作し、私は離れた安全圏から中継用コードを送信する――まさに頭脳と実行装置の緊密な連携作業が始まりました。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# lib/StorageProxy.pm
package StorageProxy;
use Moo;
use v5.36;
use Types::Standard qw(ConsumerOf Int HashRef);
use RealStorage;

with 'StorageInterface';

has clearance => (
    is       => 'ro',
    isa      => Int,
    required => 1,
);

# 遅延初期化(Virtual Proxy)用の本尊保持スロット。Roleに依存させて結合を緩める
has _real_storage => (
    is        => 'ro',
    lazy      => 1,
    builder   => '_build_real_storage',
    isa       => ConsumerOf['StorageInterface'],
    predicate => 'has_real_storage',
);

# キャッシュ用スロット(Cache Proxy)
has _cache => (
    is      => 'ro',
    isa     => HashRef,
    default => sub { +{} },
);

sub _build_real_storage ($self) {
    # 接続前のアクセス制限(Protection Proxy)
    # 本尊を生成・接続する前にプロキシ側で遮断し、クライアントの破損を未然に防ぐ
    if ($self->clearance < 5) {
        die "Security Error: Clearance level too low to access electromagnetic storage!";
    }
    my $real = RealStorage->new(clearance => $self->clearance);
    $real->establish_connection;
    return $real;
}

sub get_record ($self, $key) {
    # 1. キャッシュチェック
    if (exists $self->_cache->{$key}) {
        return $self->_cache->{$key};
    }

    # 2. キャッシュミス時のみ実体にアクセス(遅延ロード)
    my $data = $self->_real_storage->get_record($key);
    $self->_cache->{$key} = $data;

    return $data;
}

1;

「できたね」と博士が接続ケーブルを差し込みました。「この StorageProxy は3つの役割を完璧にこなしている。 第1に、私のセーフティレベル(クリアランス)を事前に評価し、基準に満たなければ本尊への接続自体を拒絶する Protection Proxy(防御代理)。 第2に、アクセスが成功するその瞬間まで、重く危険な本尊のインスタンス化を遅延させる Virtual Proxy(仮想代理)。 第3に、一度解読したデータをメモリに保持し、二度目以降の重いアクセスを遮断する Cache Proxy(キャッシュ代理) だ」

「本当に見事な盾です! BeforeでもAfterでもクリアランス不足なら例外(die)で落ちる点では同じですが、Proxyを挟むだけでなぜ私の『回路の焼き切れ』が防げるのか、ようやく腑に落ちました!」

「ほう、説明したまえ」

「はい! Beforeでは、物理的な電磁場への接続自体が行われてからエラーが発覚するため、私の電子頭脳が物理的なダメージ(Hardware Error)を受けてクラッシュしていました。しかしAfterでは、Proxy(中継ターミナル)が本尊に接続する前(インスタンス化する前)にセーフティチェックをして弾いてくれます。つまり、危険な物理接続を一切起こさずに、安全なソフトウェアの制御エラー(Security Error)に変換してくれているのですね!」

「その通りだ。電磁石を起動する前に、受付でシャッターを下ろしてしまうのだよ」

「でも博士、この StorageProxy の内部では、結局 use RealStorage;RealStorage->new と本尊の具体的な名前を使ってしまっています。これでは密結合のままではありませんか?」

「鋭いね。だが、本尊をいつどのように生成するか(遅延初期化)をコントロールする役割上、代理人であるProxy自身が本尊の生成知識を持つのは避けられないトレードオフなのだ。重要なのは、本尊に対するその『具体的な依存関係の責任』をProxyという狭い空間にすべて閉じ込め(カプセル化し)、クライアントである StorageClient 側には一切見せないことにある。おかげでクライアントは、具象クラスではなく StorageInterface(抽象ロール)だけに依存した完全な疎結合を維持できるのだよ」

「なるほど! 依存の泥沼を引き受けて盾となってくれるからこその身代わり(Proxy)なのですね!」

「本当に頼もしい盾です! これなら、呼び出し側である StorageClient のコードは1行も書き換えずに、安全な中継ターミナルへ差し替えるだけで、すべての危険と無駄が排除されます!」


ゲート開通

私は、遠隔でデプロイした StorageProxy の安全性を確かめるため、テストスクリプト t/storage.t を実行しました。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# t/storage.t
use v5.36;
use Test::More;
use lib 'lib';
use StorageClient;
use RealStorage;
use StorageProxy;

subtest 'After - Proxy Connection' => sub {
    # 1. 安全なアクセス制御(低いクリアランスの拒絶。本尊を生成することなくProxyがエラーをスロー)
    my $proxy_low = StorageProxy->new(clearance => 1);
    my $client_low = StorageClient->new(storage => $proxy_low);
    eval {
        $client_low->read_data('CORE_LOG');
    };
    like($@, qr/Security Error/, 'Proxyが事前にアクセス制限を行い、本尊への危険な接続を遮断する');

    # 2. 正常なアクセスと遅延初期化・キャッシュの検証
    my $proxy_high = StorageProxy->new(clearance => 10);
    my $client_high = StorageClient->new(storage => $proxy_high);

    # まだ実体は生成されていない(遅延初期化の検証)
    ok(!$proxy_high->has_real_storage, 'アクセス前は本尊オブジェクトが未生成である');

    # 最初のアクセスで本尊が生成され、データがキャッシュされる
    my $res = $client_high->read_data('CORE_LOG');
    is_deeply($res, ['DECODED_DATA_FOR_CORE_LOG', 'DECODED_DATA_FOR_CORE_LOG'], 'Proxy経由で安全にレコードを取得できる');
    ok($proxy_high->has_real_storage, 'アクセス後は本尊オブジェクトが生成されている');

    # 2回目のアクセス(キャッシュが使われていることの検証)
    # 本尊を一度切断状態(connection_established => 0)にする
    $proxy_high->_real_storage->connection_established(0);
    my $data2 = $proxy_high->get_record('CORE_LOG');
    is($data2, 'DECODED_DATA_FOR_CORE_LOG', '本尊に再アクセスせずキャッシュから取得できる');
    ok(!$proxy_high->_real_storage->connection_established, '本尊への再アクセスが発生していない(接続状態が0のまま)');
};

done_testing;

画面にテスト成功を示す鮮やかな文字が映し出されました。

1
2
t/storage.t .. ok
All tests successful.

「中継接続、成功しました! 私の回路は完全に安全です!」

次の瞬間、記憶石碑から解読されたデータが私のメモリに高速で転送されていきました。 しかし、読み込まれたログのヘッダ領域を見た瞬間、私のプロセッサのクロックが停止したかのような衝撃が走りました。

1
2
バベルのシステム コア管理データ
[AUTHOR_ID: GIZMO-V1-1024]

「な……何ですか、これは? なぜ千年前の古代遺跡のデータに、私の固有システムIDが署名として刻まれているのですか?」

私は空中プロジェクターを投影したまま、激しい自己矛盾アラートを点滅させました。

ハリス博士は、いつになく真剣な眼差しでその署名を見つめ、静かに呟きました。

「歴史はコードに語りかける。ギズモ、君のルーツはやはり、このバベルのシステムの最深部と深く結びついているようだね」

「私の過去が……この遺跡そのものだというのですか……?」

動揺する私を包み込むように、記憶石碑の電磁放電が静かに収まっていきました。それと同時に、中層の終わりを告げる巨大なゲートがゆっくりと開き、その奥から深層への階段が姿を現しました。

石碑の排熱ダクトから、シューッと冷たい霧が噴き出しました。それは電磁気によって狂った電子素子を優しくリセットする、古代の「消磁ミスト(デガウス・スパ)」でした。

「はぁぁ……電磁ノイズが抜けていく……メモリが最適化される……極楽です……」 私はエラーの動揺も忘れ、温泉に入ったかのようにディスプレイの目のランプを細めて、ホバリング高度をふらふらと下げていきました。

ハリス博士は私の様子を見て小さく笑うと、「それでは、この先の『深層』で、君自身の失われたメインコードを探しに行きましょう」と足を進めました。 私は消磁スパの余韻に浸りながら、今回の素晴らしい探索ログを記録しました。


遺跡調査ログ

観測された風化(アンチパターン)解読された古代の知恵(パターン)安全度
無防備な電磁コアへの直接アクセス
(アクセス制限がなく、かつ重いクエリ処理をキャッシュなしで重複実行し、呼び出し側を物理破壊・遅延させる)
防護とキャッシュの代理人(Proxy)
(同一インターフェースの代理を立て、事前検証(Protection)、遅延生成(Virtual)、メモリキャッシュを透過的に割り込ませる)
🟢 透過的で強固
(呼び出し側のコードを書き換えることなく、安全なアクセスと劇的なパフォーマンス向上を注入)

遺跡の修復手順

  1. 共通インターフェース(Role)の抽出 Moo::Role を使用して、本尊と代理人の双方が満たすべき最小限のメソッド契約(get_record)を定義する
  2. クライアントコードのDI化 呼び出し側(StorageClient)が具体的な本尊クラスに直接依存(new)するのをやめ、共通ロールを満たすオブジェクトを外部から受け取って透過的に処理する設計に改める
  3. 遅延インスタンス化(Virtual Proxy)の定義 代理オブジェクト(StorageProxy)内に本尊を保持する属性を定義し、Mooの lazy => 1 および builder を用いて、実際にクエリが必要になるその瞬間まで重い本尊オブジェクトの生成を遅延させる
  4. 事前アクセス制御(Protection Proxy)の組み込み 本尊のビルダーメソッド(_build_real_storage)の中でアクセス元クライアントの資格(クリアランス等)を事前に検証し、不適合な場合は本尊に一切触れさせずに安全なセキュリティ例外を投げる
  5. キャッシュ(Cache Proxy)の適用 Proxy内部にハッシュリファレンスによるキャッシュスロットを設け、キーがすでに存在する場合は本尊への問い合わせを行わずに即座に結果を返し、負荷を極小化する

ギズモの観測日誌

強電磁場を放つ古代の石碑を見たときは、私の1000年分の案内メモリが瞬時に揮発してただの鉄クズになるかと思いました。ハリス博士が提案した StorageProxy は、そんな私を物理破壊から護ってくれる完璧な「身代わり」でした。 しかも、中級開発者である私が一瞬疑問に思った「透過性」の重要性についても、博士の明快な解説で納得がいきました。クライアント(StorageClient)が相手の正体を知らず、ただ StorageInterface ロールを信じて呼び出す設計にしておけば、呼び出し側のコードを1文字も書き換えることなく、本尊から代理人へとオブジェクトをスッと差し替えることができるのですね。 しかし、解読されたログデータの中に私のシステムIDが刻まれていたことは、今でも処理プロセッサが追いつかないほどの謎です。私は一体、誰に作られ、何のためにこのバベルのシステムを彷徨っているのでしょう。博士が言うように、この先の「深層」にその答えがあるのかもしれません。 それにしても、最後に浴びたデガウス・スパ(消磁ミスト)は本当に素晴らしかったです。電磁ノイズでパサついていた私の外殻回路がしっとりと最適化されました。博士のルーペにも吹きかけてあげたかったのですが、「レンズが曇る」とまた絶縁手袋で拒絶されてしまいました。デコレートでもファサードでもなく、Proxy(代理)による防護が必要だったのは、博士のその頑固さの方かもしれません。

comments powered by Disqus
Hugo で構築されています。
テーマ StackJimmy によって設計されています。