RedisのArray型――長い開発の短い物語
新しいArrayというデータ型の開発を始めたのは、1月の初めのことでした。PRがリポジトリにマージされたのはようやく今で、このコードは4か月かけてじっくり仕込んできたことになります。実装は一応パートタイムで進めていました(一応というのは、実際には何週間もフルタイムでやっていたからで、キーボードから離れるのはなかなか難しいものです)。LLMがなかったとしても、この実装自体は4か月あれば自分でもできたでしょう。変わったのは、同じ期間でそれ以外にもたくさんのことができたという点です。これから、その顛末を手短にお話しします。
最初の1か月は、ひたすら仕様書を書いていました。なぜ新しいデータ型が必要なのか、Cの構造体をどうするか、どのような疎な表現を用いるか、リングバッファやARINSERTにおける配列カーソルの厳密なセマンティクスは何か。何日もかけて長い仕様書を手で書き始め、当初はOpusとペアを組み、やがてGPT 5.3がリリースされると、設計も開発もすべてCodexに切り替えました。それ以来、システムプログラミングのタスクではGPT 5.xだけを使っています。AIのおかげで、仕様は大きく進化しました。フィードバックを何度も往復させ、どの設計が最善か、どこで妥協すべきか、何が作り込みすぎで何がそうでないかといった知的な議論を重ねた結果です。
2か月目からは、自動プログラミング(お好みでオートコーディングと呼んでいただいても構いません)で実装を始め、生成されたコードを常にレビューしていました。そこで、選んだ間接参照の階層が間違っていることに気づきました。ARSET myarray 293842948324 foo のように実行しても、巨大なメモリ確保なしで正しく動いてほしいと強く思っていたのです。当初用意していたディレクトリ+スライス(スパースとデンス)の2階層では足りませんでした。AIがいたおかげで妥協せず、もう一歩踏み込むことにしました。特定の条件を満たすと、データ構造は内部で形を変え、スライスされたデンスなディレクトリを束ねたスーパーディレクトリとなり、そこから実際の配列スライス(デフォルトで1スライスあたり4096要素)を指すようになります。この設計により、求めていた「内部的にはあくまで配列である」という表現と、狙っていたメモリ特性を保ちつつ、ARSCANやARPOPでは範囲の広さではなく存在する要素数に比例した時間で既存の配列を走査できるようになりました。
次は、すべてのコードを一行一行読み返す段階でした。すべては動いていましたし、この型はAIのおかげで膨大なテストも備えていましたが、表面的に動くことと最適であることは別問題です。望ましくない小さな非効率や設計ミスがあちこちで見つかったため、多くのモジュールを手作業とAIの支援で書き直す作業を始めました。その段階が終わると、3か月目にはさまざまな方法で実装にストレステストをかけ始めました。次第に、これは本当に堅牢で、有用で、よく設計されているという確信が持てるようになりました。
そして……それが起きました。データ構造が使いやすいかどうか、さまざまなユースケースを想定している中で、試しにMarkdownファイルをRedisのArrayに入れてみたのです。ファイルはこのデータ構造と非常に相性が良いからです。ちょうどその頃、別の目的でエージェントを使った作業をしていて、自分が必要としていたスキル用のMarkdownファイルを一元管理するナレッジベースが作れることに気づきました。そこで自分の必要性から、ARGREPを実装することにしたのです。ただ、正規表現も欲しい。どのライブラリを選ぶべきでしょうか?
最終的に選んだのはTREでした(Ville Laurikariさん、ありがとうございます!)。Redisで正規表現を扱うなら、時間的にも空間的にも病的なパターンが存在しないことを確信したいからです。ただTREは、foo|bar|zap のようなマッチという、特定の、それでいて極めて有用なケースで非常に非効率でした。そこでGPTの助けを借りて最適化し、潜在的なセキュリティ上の問題をいくつか修正し、テストを拡充しました。これですべてが揃いました。
結局、一番大きな気づきは何だったかお分かりでしょうか。高品質なシステムプログラミングでは、今でも自分自身が深く関わり続ける必要があります。ただ、AIがあったことで、そうでなければ避けていたであろう複雑さの領域にまで踏み込むことができました。AIは二つの面でセーフティネットになってくれました。一つは、ひたすら骨が折れる大規模な作業(後から追加してテストした32ビット対応のようなもの)、もう一つは、複雑なアルゴリズムに明白なバグがないことを保証するために必要な仮想的な労働力です。最初の巨大な仕様書を書いたことが、その後の作業全体の鍵でした。それはsparsearray.cやt_array.cの一行一行をレビューし、合わない部分はすべて修正していく際の拠り所でもありました。
ユースケースについてはここでは触れません。PR自体のメッセージの中で詳しく説明するようにしたからです:
https://github.com/redis/redis/pull/15162
ここで同じことを繰り返してもあまり意味がありません。ただ一言、Redisにもそろそろ、数値インデックス自体がセマンティクスの一部となるデータ型が必要だと、心から思っています。
ArrayのPRが近いうちに受け入れられ、新たに開かれるユースケースの恩恵をみんなで受けられることを願っています。もちろん、フィードバックは歓迎します。ありがとうございました。
記事をランダムに読む