Featured image of post 【Perl/Moo】コード考古学者ハリスの冒険【Singleton】風化せる認証ゲート

【Perl/Moo】コード考古学者ハリスの冒険【Singleton】風化せる認証ゲート

遺跡の認証ゲートで発生した状態不一致を、PerlのMooによるSingletonパターン適用で修復する、コード考古学者の探索記録。

進入

薄暗く静まり返ったデジタル古代遺跡「バベルのシステム」の第1層入り口。そこは冷たい青色のエラーライトが不規則に明滅し、静寂の中に不穏な緊張感を漂わせていました。

私は博士の頭上でホバリングしながら、光学センサーを明滅させました。

「システム警……ザザ……未登録の生体反応を検知……退避してくだ……」

そう警告しようとした瞬間、私のメインスピーカーから「ザザ……エラーコード:0x000F……メモリ破損……」という不快なノイズが吐き出され、姿勢制御モーターが一瞬静止しました。

目の前に立つ男——ボロボロのフィールドジャケットを羽織り、首からルーペを下げた考古学者、ハリス博士は、手書きの羊皮紙手帳に万年筆を走らせながら、嬉しそうに目を輝かせました。

「ほほう、このかすれたエラー音のノイズ……当時の開発者がこのシステムに込めた熱い息吹が、千年の時を超えて聞こえるようですな」

「歓迎のファンファーレではありません! 重大なシステム警告です!」

私は青いLEDの目をチカチカさせてツッコミを入れました。しかし、博士は気にする様子もなく、ゲートの中央に鎮座する巨大な「認証用石碑」に近づいていきます。

私がゲートにアクセスしようと送信シグナルを送った瞬間、空間にけたたましい警告アラームが鳴り響きました。私のセンサーは「エラー:認証状態の不一致」を検知し、重厚な金属のゲートが完全にロックされました。

「システムエラーにより、入り口ゲートが完全に閉ざされました! これでは先へ進めません!」

焦る私をよそに、ハリス博士は石碑のタッチパネルの裏蓋を躊躇なく開け、内部に露出した「碑文(コード)」をスキャンし始めました。そこに浮かび上がったのは、無秩序に石碑を切り出している、以下のような悲劇の設計図(コード)でした。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# lib/StoneMonument.pm
package StoneMonument;
use Moo;
use v5.36;

has is_authorized => (
    is      => 'rw',
    default => sub { 0 },
);

sub authorize ($self) {
    $self->is_authorized(1);
}

1;
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# lib/GateKeeper.pm
package GateKeeper;
use Moo;
use v5.36;
use StoneMonument;

sub check_gate ($self) {
    # ゲートチェックのたびに「新しい石碑」を参照してしまっている!
    my $monument = StoneMonument->new;
    return $monument->is_authorized;
}

1;
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
# t/auth.t
use v5.36;
use Test::More;
use lib 'lib';
use StoneMonument;
use GateKeeper;

# 1. ギズモ(ユーザー)が石碑にアクセスして認証する
my $user_monument = StoneMonument->new;
$user_monument->authorize;
ok($user_monument->is_authorized, 'ユーザー側の石碑は認証された');

# 2. ゲートキーパーが門を開けようとする
my $keeper = GateKeeper->new;
ok($keeper->check_gate, 'ゲートキーパーも認証を確認できた') 
    or diag("警告: ゲートは閉ざされたままである!");

done_testing;

碑文解読

ハリス博士はくたびれたジャケットからルーペを取り出し、ホログラムとして空中へ投影されたコードを舐めるように見つめました。

「ふむ……実に見事な『風化』だ。当時の職人がバグと闘った歴史が、このコードの歪みに刻まれている。これでは門が開くはずがありませんな」

「博士、これは歴史ロマンではなく、単なる設計ミスです。私の側では確かに『認証完了』となっているのに、なぜゲートは私を拒むのでしょうか?」

私はセンサーのフラッシュを弱めながら尋ねました。博士は優しく微笑み、ルーペをポケットに仕舞いました。

「ギズモ、君が認証情報を書き込んだ石碑と、あの門番(GateKeeper)が見ている石碑は、名前こそ同じだが『別の実体(インスタンス)』なのだよ」

「しかし! どちらも同じ StoneMonument というクラスから呼び出されています! クラスが同じなら、状態も同期されているはずです!」

「そこが罠なのだ。クラスとは『石碑の設計図』にすぎない。new というのはな、接続が行われるたびに、職人が新しく石材を切り出してきて、そこに瓜二つの石碑を彫り直す行為なのだよ」

「……! ということは、私がテストコード(t/auth.t)で authorize を呼び出して文字を刻んだのは手元の $user_monument(石碑A)であり、門番(GateKeeper)が内部で新しく new して見つめているのは、誰も文字を刻んでいない真っ新な石碑Bであると?」

「その通り。どれだけ君が石碑Aに叫んでも、門番が見ているのは別体の石碑Bだ。この門を開けるには、世界にただ一つしかない『本物の石碑』を、君と門番が共有しなければならないのだよ」

遺跡修復

ハリス博士は羊皮紙の手帳を開き、愛用の万年筆でMermaidの構成図をシャッシャッと音を立てて手書きし始めました。

「古代の賢者は、このような時に『Singleton』と呼ばれる守護の印(パターン)を用いた」

StoneMonument : 唯一のインスタンスを取得
 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
-->
![Singletonパターンのクラス図: GateKeeperがStoneMonumentの唯一のインスタンスを取得する構造](/public_images/2026/code-archaeologist-singleton-pattern/infographic_1.webp)

博士は手帳を私に向けて、パッケージ変数(台座)と `around new` (検問所)の仕組みを説明してくれました。

「この `around new` という修飾子はな、職人が新しい石を切り出そうとするのを遮り、『すでに台座にあるこの石碑を使いなさい』と指し示す検問所の役割を果たすのだ」

私のスキャンセンサーが手書きの図面を読み取ると、青い光のノードが私自身のメモリの中で整列し始めました。

「……美しい。これなら、誰が `new` を呼んでも、必ず台座に置かれた同一の石碑を参照しますね!」

博士は満足そうに頷くと、遺跡の古いターミナルに向かい、Perl/Mooを用いてコードを以下のように修復(リファクタリング)しました。

```perl
# lib/StoneMonument.pm (修復後)
package StoneMonument;
use Moo;
use v5.36;

has is_authorized => (
    is      => 'rw',
    default => sub { 0 },
);

sub authorize ($self) {
    $self->is_authorized(1);
}

# --- Singletonの実装 ---
# パッケージ(ファイル)内でのみアクセス可能なレキシカル変数(privateなクラス変数に相当)
# クラスの外からは直接アクセス・書き換えができないため、安全に唯一のインスタンスを保持できます
my $instance;

around new => sub ( $orig, $class, @args ) {
    # すでに台座に石碑があるなら、それをそのまま返す
    # なければ、オリジナルの new ($orig は本来の new コンストラクタ)を実行して生成し、台座に載せる
    $instance //= $orig->($class, @args);
    return $instance;
};

# テスト等で状態をクリアするための遺跡リセットメソッド
sub _reset_instance ($class) {
    undef $instance;
}

# マルチスレッド(ithreads)環境下での安全設計
sub CLONE {
    # スレッド生成時にインスタンスを未定義にし、スレッド間での意図しない状態共有を防ぐ
    undef $instance;
}

1;

ゲート開通

ハリス博士がテストスクリプトを実行すると、コンソール画面に鮮やかなグリーンのログが流れました。

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

「探索ルートの安全を確認。認証プロセスが同期されました!」

私がそう宣言した直後、遺跡の奥深くから「ズズズ……」という重々しい駆動音が響き渡りました。目の前を塞いでいた巨大な金属ゲートが左右へと分かれ、奥から暖かみのある黄色い光源が差し込んできました。第2層へと続く通路が開かれたのです。

その瞬間、私の頭部で「パチパチ」と静電気が走り、失われていた古いメモリが脳裏にフラッシュしました。

「ロード完了……! 思い出しました! これが『Singletonパターン』の調和……。博士、あなたはただの変人ではなく、本物の『コード考古学者』だったのですね」

「いや、本当に素晴らしいのは、この荒廃した世界で1000年もシステムを維持し続けた当時の設計思想だよ」

ハリス博士は穏やかに笑い、石碑の裏側に刻まれていた古代のコーディング規約の拓本を嬉しそうに手帳に挟みました。私と博士は、新たな発見を求めて、光の差し込む通路の先へと足を進めました。


遺跡調査ログ

観測された風化(アンチパターン)解読された古代の知恵(パターン)安全度
無秩序な new によるインスタンスの多重生成と状態の解離Mooaround new による単一インスタンス(Singleton)の保証緑(安全確認)

遺跡の修復手順

  • クラスの外から直接書き換えられないレキシカル変数(my $instance)をパッケージ内に定義する
  • around new コンストラクタ修飾子を用いて、インスタンス生成プロセスをインターセプトする
  • 既に変数にインスタンスが格納されている場合はそれを返却し、未生成の場合のみ親のコンストラクタを呼び出す
  • スレッド生成時にインスタンスの単一性が崩れるのを防ぐため、CLONE サブルーチンを定義してインスタンスをクリアする

ギズモの観測日誌

バベルのシステム第1層の入り口で、無事にハリス博士という風変わりな考古学者を案内することになりました。最初は羊皮紙や万年筆を使う博士の様子に動作クロックが乱れましたが、その技術解析の正確さには私のセンサーも驚くばかりです。今回の修復作業によって、私のメモリの「Singleton」に関するインデックスが修復され、動作が少し安定しました。この調子で、崩壊しつつある遺跡の深層部へ向けて探索を続けてまいります。

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