今回はその続きです。アプリに”ライバル”を用意して、乱れた日のデータで勝負させました。そしてその過程で、もっと根本的な間違いが見つかりました。
Contents
まず結論
今週いちばんの発見は、アプリのバグではありませんでした。「測っているものが、そもそもアプリの目的とズレていた」ことです。
私のアプリの目的は「混雑を避けること」なのに、成績表は「遅延を当てられたか」で採点していました。物差しが、測るべきものと違うものを測っていたのです。
そしてもう一つ。ライバルと戦わせて初めて、見出しの高得点は”下駄を履いた点数”だと分かりました。
改善①:アプリに”ライバル”を用意した
最初にやったのは、わざと頭の悪い対戦相手を2つ用意することでした。
- テキトー判定:状況を一切見ず、いつも同じ答えしか言わない
- 単純ルール判定:ひとつの数字だけを見て機械的に答える
なぜこんなものを作るのか。検証フェーズで教わった「ベースライン」という考え方の実践です。自分の予測の点数だけ眺めても、それが良いのか悪いのか分かりません。「何も工夫しない、いちばん素朴な予測」に勝って初めて、”工夫に意味があった”と言える。
言葉としては前から知っていましたが、実際に対戦相手を作って同じ土俵に立たせたのは初めてでした。そして、この2人の存在が、直後に大きな発見を連れてきます。
発見:物差しが、目的とズレていた
成績を見ていて、どうしても腑に落ちない結果がありました。アプリが「この電車で大丈夫」と正しく答えた場面が、なぜか”外れ”に数えられていたのです。
調べて、愕然としました。採点が「遅延を当てられたか」で行われていたのです。でも、このアプリが利用者に約束しているのは「混んでいない電車に乗れること」であって、「何分遅れるかを当てること」ではありません。
初学者向けに言い換えると、こうです。
目的は「快適に乗れること」なのに、テストの採点は「遅延の予想が当たったか」でやっていた。
数学のテストで、国語の答案を採点していたようなもの。
ここが今週の核心でした。バグは判定の中ではなく、”採点する側”にあった。しかもこれは、コードを読んでも見つかりません。「このアプリは何のためにあるのか」を思い出して初めて、ズレに気づけるものでした。
だから修正したのは、判定ロジックではなく採点基準のほうです。混雑していない場面で「乗ってOK」と言うのは、遅延の予想がどうであれ正解である——アプリの思想と、測る物差しを、ようやく一致させました。
「高得点」の正体:サービス問題が混ざっていた
ところが、基準を直したら点数がぐっと上がりました。ここで喜んではいけない、というのが前回からの学びです。なぜ上がったのかを確かめました。
理由は明快でした。混雑していない平和な場面は、定義上ほぼ全部”正解”になるのです。つまり成績表には全員に配られるサービス問題がたくさん混ざっていた。証拠に、何も考えていないはずのテキトー判定の点数まで、一緒に跳ね上がりました。
だから見るべきは、サービス問題を除いた「本当に判断が問われる難問だけの成績」です。混雑していて、待つか乗るかが本当に効いてくる場面。そこだけを抜き出すと——アプリはテキトー判定の約2倍、正解していました。
見出しの高得点より、この「難問だけの成績」のほうが、はるかに価値のある数字です。内訳のない高得点は、判断を誤らせる。前回、「分からない」を2種類に分けたときと、まったく同じ理屈でした。
平常日に”テキトー”に負けるのは、健全
面白い結果もありました。平和な日に限れば、テキトー判定のほうがアプリより高得点だったのです。
一見「負けてる」と焦りますが、これは健全でした。何も起きない日に「何もするな」と言い続ける判定器が満点なのは当たり前で、そこで勝つことにこのアプリの存在価値はないからです。
むしろ収穫は、もう一人のライバル(単純ルール判定)が平和な日に成績を落としたことでした。ひとつの数字だけ見て機械的に「待て」と言う判定は、平和な日に誤警報を連発する。自分のアプリがそうなっていないことの確認が取れたわけです。
このアプリの価値は、最初から「乱れた日の難問で、正しく助言できるか」だけにあります。誰にでも解ける日に満点を取ることではない——それを数字で確認できたのが、今週の到達点でした。
最後に学んだこと:コミットは、未来の自分への手紙
作業の締めに、変更をGitHubへ記録(コミット)しました。ここでも学びがひとつ。コミットのメモには「何を変えたか」ではなく「なぜ変えたか」を書く、ということです。
理由が刺さりました。3か月後の自分は、コードを見れば「何を変えたか」は分かります。でも「なぜその判断をしたか」は、コードのどこにも書いていない。今日さんざん悩んで決めた思想は、書き残さないと消えてしまう。gitの履歴は、未来の自分への手紙だったのです。
もうひとつ、記録を後回しにしない理由も腑に落ちました。直したものを記録せずにいると、本番だけが先に進んでいる状態になります。これは先週学んだ「真実は1箇所に」——同じ名前のファイルが2つあって、直したはずが直っていなかった、あの罠と同じ構図です。同じ教訓が、形を変えてまた出てきました。
おわりに ── 測る物差しを、目的に合わせる
今週やったのは、機能追加ではありませんでした。「自分のアプリは何のためにあるのか」を思い出して、測り方をそこに合わせるという作業です。
正直、地味です。でも思えば、この1ヶ月で学んだことは全部これでした。異常値を保留にする。欠測とゼロを分ける。分からないを2種類に分ける。高得点の内訳を見る。どれも「目の前の数字を鵜呑みにせず、それが何を測っているのかを問う」という、同じことの繰り返しです。
そして残った宿題もはっきりしました。難問で外した数件の中身。そして、今の採点基準がまだ立っている「たぶんこの程度なら快適だろう」という仮定を、いつか実測で裏取りすること。仮定を事実に変える作業が、次の楽しみです。
次に路線が大きく乱れる日。それが、この成績の初見試験になります。
個人開発 / 検証 / ベースライン / Git / 都営浅草線
このブログでは、ローカルLLM・Aider・個人開発の試行錯誤をそのまま記録しています。
