こんにちは!any 株式会社でプロダクトチームに所属しているエンジニアのなおとぅ(@Rasukarusan)です!
この記事は、any Product Team Advent Calendar 2025 シリーズ3の15日目の記事になります。
職場にて
とあるシステムの「削除処理」について同僚と話していた。
その処理は、対象データを検知するたびに、外部サービスの削除 API を毎回呼び出しており、パフォーマンス面で問題があった。
どうにかしたいな〜と思い、同僚に相談してみた。
💁 僕「これ、検知するたびにAPI呼び出すんじゃなくて、一旦配列に溜めておいて、最後にある程度まとめて処理するのはどうすかね」
🙋♂️ 同僚「お、いいですね。僕それやっておきますよ」
💁 僕「マジか大感謝アザーマウスなり🙏」
想像していた 100 倍エレガントなコードがきた
数日後、同僚が持ってきたのは自分が思い描いていたコードとはまったく別物だった。
自分の案は単純に、
- 対象を配列に溜める
- 処理の最後でループしてまとめて実行する
という、いかにも一般的で、誰もが最初に思いつくやつだった。
しかし同僚が出してきたのは、「任意の処理をバッチ化するための仕組み」 だった。
session = createSession('file_deleted')
session.add(file_id)
session.complete()
この 3 つの操作だけで、どんな種類のイベントでも同じように扱える。
途中の細かい実装は隠蔽されており、使う側は意識しなくていい。
あの時話していたのは単なる削除処理の改善だったのに、
同僚が持ってきたのは複数の種類のイベントを、汎用的にバッチ処理するための抽象レイヤーだった。
しかもデータを溜める所の内部実装に DataLoader を使っているのも鼻血が出るほど美しかった。
DataLoader は通常 GraphQL でよく使われるもので、
- 複数のデータ取得要求をまとめて 1 回の問い合わせにする
- 同じキーのデータがすでに取得済みなら、再問い合わせをせずキャッシュから返す
という処理をしてくれる。GraphQL でよく発生する N+1 問題の解決や、データベースへのアクセス回数を減らしてくれるためのライブラリである。
同僚は、この DataLoader を今回の 「任意の処理をバッチ化するための仕組み」に組み込んでいた。
イベントが発生するたびに都度外部サービスへ送信するのではなく、短いスパンで連続して発生したリクエストが裏側で自動的に集約され、ひとかたまりのバッチとして扱われ、その単位で一括送信されるようになっていた。
つまり、本来であれば
溜める → タイミングを決める → ループで送る
といった手動の段取りが必要になるところが、溜まる→まとまる→送られるという一連の流れごとフレームワーク側に吸収されている。呼び出し側はただイベントを追加するだけでよく、「いつ送るか」「どれをまとめるか」 といった判断はすべて内部で最適化される仕組みになっていたのである。
僕とAIの思考の限界
最近のAIは賢い。
「毎回 API 叩くのは非効率だからまとめたい」と言えば、ちゃんとコードも出してくれる。
でも、それはあくまで局所解だ。
おそらくだが、何も考えずに AI に頼んだら以下のようなコードを出してくるだろう、
const bucket = [];
// ...何かしらの処理
bucket.push(id);
// 最後に20件ずつまとめて送信
const BATCH_SIZE = 20;
for (let i = 0; i < bucket.length; i += BATCH_SIZE) {
const batch = bucket.slice(i, i + BATCH_SIZE);
await deleteAPI(batch); // 20件単位でAPI呼び出し
}
まあこれでも普通に動く。動くんだが、素直すぎるコードだし、例えば「ファイルのダウンロード」など他でも同じようなことが必要になった際、毎回これを書く羽目になる。
しかし同僚のアプローチは違った。
「削除処理の改善」という個別の問題として捉えるのではなく、「データを溜めて、まとめて何かする」という共通パターンとして捉えた。
そして、GraphQL で使われる DataLoader の仕組みを別の用途に応用し、どんな処理でも同じ使い方ができる統一的なインターフェースを作り上げたのだ。
素晴らしすぎる、、、どうやったらこの発想になるのか聞いてみた。
💁 僕「このバッチの仕組み最高なんやが、どうやってこの発想に至ったんやろか??」
🙋♂️ 同僚「うーん、“データを溜めてからまとめて何かする”っていうのは、DataLoader だなーと思ったのでまあそこから。」
ふふ。ワイはあの時、配列のことしか頭になかったやで、、😇
これはAIに出せない
少なくとも「僕のAI」からは一生出てこないコードだと思った。
仮に配列の処理がいくつもの場面に出てきてから、「共通化したい」という願望を AI に投げても、内部に DataLoader を使い、統一的なインターフェースを提供するバッチ処理レイヤーなんてものは、100 万回 AI とやりとりしても生まれる気がしない。
文脈を読み替えたり、前提そのものを跳び越えるような発想は、人間だからこそできることだと思った。
終わりに
全部AIに任せればいいか〜と思うことが増えてきたけど、ところどころで人間力が試される時がくる。
いざって時にビシッと人間力を示すことができる人になりたい。
おまけ
ちなみに DataLoader 自体のコードは 500 行にも満たない 1 つのファイルで構成されていて、これもまた非常に美しい。こんなにシンプルなのにもたらす効果は絶大だ。
かつて別の同僚が「DataLoader のコードは一回見ておく価値あるっすよ!」と言っていて、実際その時コードを見て「ほぉ〜」と思った記憶はあるんだが、今回全く思いつかんかったな😇
any 株式会社では ナレッジ経営クラウド Qast のエンジニアを絶賛募集中です。
是非 採用ページ をご覧ください!
エンジニア組織 / 文化について詳しく知りたい方はこちら