「最近、少しボケてきたかもしれない」とオカンが言いました。
元々オカンは天然でしたが、心配になりました。
こういう時、息子にできることは少なく……。
何かできることないかなぁ……と検討した結果、私は自分が実践しているトランプ記憶術(メモリーパレス)を、おかんの脳内トレーニングとして導入してみることにしました。
ルールは、ランダムにシャッフルされたトランプの並び順をイメージに変換して記憶し、その記憶時間を計測するというものです。
最初はスペードの13枚からスタートします。「スペードの1はスイカ」「スペードの2はスニーカー」といった具合にあらかじめ固定したイメージを紐づけて順番に記憶し、約10分間のインターバルを置いた後、もう1つのトランプの山を使って「全く同じ並び順」を再現(アウトプット)します。このステップを重ね、最終的には52枚のフルデッキすべてを完璧にイメージだけで記憶・再現できるようにすることが最終目的です。
おかんが日々どのステップを踏み、どれだけタイムを縮めているか、その成長プロセスを本人が実感でき、かつ離れた場所にいる私もリアルタイムで把握できる仕組みを作りたい。これが、今回のプロジェクトのすべての始まりでした。
しかし、この温かい目的からスタートしたはずのプロジェクトは、私のこれまでの「仕事の経験」という歪んだフィルターを通した結果、一時的に奇妙な手段の泥沼へと迷い込むことになりました。
「閉鎖環境の経験」がもたらしたバッチファイルへの固執
私はこれまで、外部のWebシステムやERPの導入が極めて難しく、せいぜいExcelや手元のバッチファイル程度しか使えない、いわゆる「閉鎖的なネットワーク環境」で実務を行ってきました。何か新しいITツールを導入しようとすれば、セキュリティや環境固有の制約という分厚い壁にぶち当たる環境です。
そのため、私の頭には無意識のうちに「手元で動くバッチファイル(.bat)でなんとかする」という手段の固定化(ドメインの妄執)が染み付いていました。
「おかんのパソコンのデスクトップにバッチファイルを置き、ダブルクリックしたら黒い画面が立ち上がって、そこに『13枚、〇分〇秒、スペード』と記録を入力させるようにしよう」
最初はそう考え、対話型AIであるChatGPTを相手にバッチファイルの作成を依頼しました。ChatGPTは優秀ですので、こちらの指示通りにバッチファイルを書いてくれます。しかし、やり取りを重ねるうちに、私は違和感と戦うことになりました。
「黒い画面でレコードを一つずつ正確に理解させよう」とすればするほど、プロンプトの意図が微妙にズレ、泥沼のようなデバッグ作業が続きます。「JavaScriptを使ってブラウザに命令を投げたらどうだ」「このライブラリを使えば動くのではないか」と、手段のアイデアばかりが肥大化し、開発は一向に前に進みませんでした。
何でも言うことを聞いてくれるAIだからこそ、自分が思いついた「手段」に固執し、それを盲目的にチューニングし続けてしまう。これは、要件定義における最大の罠でした。
目的への回帰:かつてPMBOKを学んだ身として要件を「再定義」する
混迷を極める対話の中で、私は、かつてBPOの業務委託(受託)案件でプロジェクトマネージャーを務め、その中でPMBOK(プロジェクトマネジメント知識体系)を学んでいた身として、最も重要となる問いに立ち返りました。
「このプロジェクトの最終目的は何か?」
それは、優れたバッチファイルを作ることでも、最新のJavaScriptライブラリを使いこなすことでもありません。「おかんが一切のストレスなく毎日トレーニングを継続でき、そのデータを私がいつでも見守れること」です。
この目的を改めて定義した瞬間、これまでこだわっていた「デスクトップで動くバッチファイル」という仕様が、いかに的外れであったかが浮き彫りになりました。
シャッフルされたトランプを極限の集中力で記憶し、さらに10分後に神経を研ぎ澄ませて別のカードで再現する。この、脳を極限まで酷使する作業を終えた直後のおかんに、わざわざパソコンを起動させ、黒い画面(CLI)にキーボードで数字やマークをカタカタと打ち込ませる仕様など、長続きするはずがありません。スマホのブラウザから、ソファやベッドに寝転びながらでも親指一本でタップできるUI/UX(ユーザー体験)こそが、目的を達成するための絶対条件でした。
私はAIとの対話をリセットし、目的から逆算した「スマホ対応の極小Webアプリ」へと要件を完全にピボット(転換)させました。
目指している「目的主導型」のデータフロー
そうして今たどり着こうとしているのが、フロントエンドを極めてシンプルな一枚のHTML、サーバーサイドをGoogle Apps Script(GAS)で構築し、データの受け皿をGoogleスプレッドシートにする構成です。
[スマートフォン(HTMLフォーム)]
│(データ送信)
▼
[Google Apps Script(API)] ──(自動追記)──► [Googleスプレッドシート]
│
└─(自動メール通知)─► [管理者(あなた)のメールボックス]
この設計であれば、おかんのスマホにアプリをインストールしてもらう必要すらありません。ブラウザのブックマークからURLを開くだけで、すぐに記録できる——そんな形を目指して、今まさに作り込んでいる最中です。
データの保全をクラウド(スプレッドシート)に一任し、入力フロントをスマートフォンに最適化する。この極小システムを試行錯誤しながら組み立てる中で、特に「おかんに使ってもらうため」に頭をひねった、認知負荷を下げる2つのコアロジックを紹介します。
コアロジック1:覚えた枚数から「必要絵柄数」を自動算出する
トランプ記憶は、覚える枚数が増えるほど使用するマーク(絵柄)の数が増えます。入力の手間を減らすため、入力された「枚数」から、必要な絵柄の数をシステム側で自動判定するようにしてみました。
以下は、GASおよびJavaScriptで共通して使えそうだと考えている、枚数から必要絵柄数を導き出す判定ロジックです。
// 枚数から必要絵柄数(1〜4)を自動判定する
function getNeedSuitsCount(cards) {
if (cards <= 13) return 1; // 13枚以下なら1種類(例:スペードのみ)
if (cards <= 26) return 2; // 26枚以下なら2種類
if (cards <= 39) return 3; // 39枚以下なら3種類
return 4; // 40枚以上なら全絵柄(4種類)
}
このシンプルなルールを挟むことで、画面上でおかんが「使用したマークの数を自分で選ぶ」という余計なステップをなくせるのではないか、と考えています。
コアロジック2:前回の記録を流用して「1秒」で入力を終わらせる
おかんが毎日トレーニングをする際、基本的には「昨日と同じ枚数、同じマーク」で繰り返し練習することが多くなるはずです。
そこで、サーバーから「前回の記録」を動的に取得し、今回の入力枚数のグループが前回と同じであれば、「前回と同じマークですか?」という確認ダイアログをポップアップ表示する——そんな仕様を今試しているところです。
// フロント側の「前回流用」判定プロセス
const lastRecord = await fetchLastRecord(); // GAS経由で最新行を取得
const currentGroup = getNeedSuitsCount(inputCards);
const lastGroup = lastRecord ? getNeedSuitsCount(Number(lastRecord.枚数)) : null;
// 前回と同じ枚数グループなら、確認ダイアログを出す
if (lastRecord && lastGroup === currentGroup) {
const isSame = await askConfirmDialog(`前回の絵柄(${lastRecord.使用絵柄})と同じですか?`);
if (isSame) {
suits = lastRecord.使用絵柄.split('/'); // 前回の絵柄をそのまま流用して送信へ
} else {
suits = await openSuitSelectionDialog(currentGroup); // 違えば新規選択
}
}
「はい」をワンタップするだけで、面倒な複数チェックボックスの選択をスキップして送信フェーズに移行できる。脳が疲れている状態のユーザーに対して、これ以上ない「有能感」と「手軽さ」を提供できたら——そんなUXのガードレールを目指して、まだ手探りで調整を続けています。
GASを外部公開する際の、地味だけど致命的な落とし穴
こうした極小システムを個人や家族間で運用しようとすると、多くのノンプログラマーが最初につまずくのが、GASを「ウェブアプリ」として公開する際の設定です。私自身、ここでしっかり足を取られました。
HTMLフォームから送信されたデータを正常に受け取るためには、GASを以下の設定でデプロイ(Webアプリ化)する必要があるようです。
- 次のユーザーとして実行: 「自分(あなたのGoogleアカウント)」
- アクセスできるユーザー: 「全員(Anyone)」
「全員」に設定しておかないと、スマートフォン(おかんのブラウザ)からアクセスした際にGoogleへのログインを要求されたり、通信エラー(CORSエラー)で送信がブロックされたりしました。「全員に公開」にして、ようやく認証不要のシンプルな入力デバイスとして機能し始める——ここに気づくまで、何度もつまずきました。
目的を見失わない対話が、真の要件定義をつくる
今回の開発プロセスは、非エンジニアである私にとって非常に貴重な学びをもたらしてくれました。
私たちは対話型AIを使うとき、ともすれば「自分の最初の思いつき(手段)」を完璧に動かすことに熱中してしまいます。しかし、どれだけ精緻にプロンプトを工夫したとしても、対話のスタート地点である「手段」が間違っていれば、出来上がるものは「誰にも使われない完璧なゴミ」になってしまいます。
本来の要件定義とは、固執化した手段を固定することではなく、目的に沿った形で何がベターであり、ベストプラクティスであるかを取捨選択(瞬別)することです。過去の自分の経験やドメインの「妄執」から脱却し、目的から逆算して要件を組み立て直す。これこそが、非エンジニアがエンジニアやAIと対話する際に最も重要となる「デジタルな対話力」の本質なのだと感じました。
おかんのために作ったこのシステムは、現在も作成中です。
おかんが毎日スマートフォンの画面をタップするたびに、私のメールボックスへ通知が届き、その成長がクラウド上で可視化されていくことを夢見ています。
固執した手段に溺れた「不便な100点のバッチファイル」よりも、目的を達成するための「1秒のWebタップ」。
それこそが、技術と人が幸福につながるための、要件定義の正しい答えなのかもしれないと思いながら、AIと格闘しております。
最後に少しだけ。私は非エンジニアなので、この記事に載せたコードは正直わからない部分が多く、ほぼ完全にAIに頼って組み上げた部分です。「ここはこう書いた方がいいよ」とか「実はこの部分、間違っていて動かなかったよ」といったことがあれば、ぜひ教えていただけると嬉しいです。温かくご指摘・ご意見いただけたら、とてもありがたく思います。