AIに書かせた機能を、まとめずに消しました。773行あります。動いていました。それでも、残すより消すほうが安全だと判断しました。
こんにちは。AIでDXを加速する専門家、ばんのです。
配信内容を2パターン用意して、どちらの反応がよかったかを比べる機能があります。いわゆるA/Bテストです。私はこれを2回作らせてしまいました。先に作らせたほうを、あとから丸ごと削除した話です。
第6回までは、作った話と直した話でした。第7回だけは捨てた話です。そして、この連載で最も怖い思いをしたのは、機能を追加したときではなく、この削除のときでした。
先に、この連載での役割分担を書いておきます。コードを書いているのはAIで、書いたものを検査しているのも別のAIです。私はコードを1行も書いていません。私の仕事は、何を作るかを決めること、何を確かめてほしいかを伝えること、そして出てきた指摘のうちどれを採用するかを決めることです。今回でいえば、消すと決めたのが私、消す作業と、消したときに何が起きるかを洗い出したのがAIです。
この記事を読むとわかること
- 同じ機能が2つ並んだとき、まとめずに消したほうがいい場合があること
- 削除の前に確かめた3つのこと
- 使われていない機能を消した瞬間に、全読者へ再送しかけた話
- 消すものと、残すものの分け方
同じ機能が、2つ並んで残っていた
同じ機能が2つある、という状態は、ある日突然できるものではありません。作った順に見ていくと、どこで止めておけばよかったかがはっきりします。
最初は、配信画面の「おまけ」として作らせた
最初に作らせたA/Bテストは、一斉配信の画面のなかにありました。配信を1本作るとき、おまけの設定として「件名を2パターン試す」を選べる形です。
使ってみて、独立した仕事だと分かった
しばらく使ってみて、これは違うと思いました。A/Bテストは配信のおまけではなく、それ自体がひとつの仕事です。テストの名前を付け、何で勝ち負けを決めるかを選び、何割の人に試すかを決め、結果を待って、勝ったほうを残り全員に送る。このように、手順がひとつながりで独立しています。
そこで、独立したメニューとして作り直してもらいました。専用の画面と、専用のデータの置き場を用意して、手順どおりに進む形です。以降は、こちらが本命になりました。
作り直したのに、古いほうを消さなかった
問題は、そのときに「古いほうを消して」と指示しなかったことです。当時はまだ、進行中のテストが残っているかもしれないと考えました。なので、画面からは選べないようにしたうえで、中身のプログラムはそのまま置いておきました。「あとで消す」という札を貼って。
その札は、そのまま1か月ほど貼りっぱなしになりました。図にすると、こういう状態です。
おまけ設定
「件名を2パターン試す」
プログラムは残っている
名前を付ける → 勝敗の条件を選ぶ → 何割に試すか決める → 結果を待つ → 勝ったほうを全員へ
まとめる、という選択肢を捨てた
同じような処理が2か所にある。ここで普通に思いつくのは、共通の部品にまとめることです。片方を消すのではなく、両方から使える1つの仕組みにする。教科書的にはこちらが正解です。
AIは、頼めば共通化もしますし、削除もします。どちらが正しいかは決めてくれません。ここは私が決めるところでした。
やめました。理由は3つあります。
理由1. まとめる作業のほうが、消す作業より工数が大きい
2つの実装は、勝ち負けの決め方も、データの持ち方も違いました。共通化するなら、どちらにも当てはまる形を新しく設計し、両方をそこへ寄せ、寄せたあとに両方が前と同じように動くことを検査する。削除なら、消して、消したあとに何も起きないことを検査するだけです。作業量は共通化のほうが数倍かかります。しかも片方は誰も使っていないのに、その片方に合わせて本命の設計を曲げることになります。
理由2. まとめたあとも、使わない側の確認工数が永久に残る
共通部分に手を入れるたび、使っていないほうも一緒に確かめないといけません。しかも、この手間は永久に続きます。
理由3. 使う予定がない
古いほうを画面から外した時点で、新しく作られる経路はもうありません。使う予定のないものを、丁寧に整えて残す意味がわかりませんでした。
3つの選択肢を、手間と残るもので並べた
| 選択肢 | 今かかる手間 | あとに残るもの |
|---|---|---|
| そのまま残す | ゼロ | 触るたびに確認が要る773行 |
| 共通の部品にまとめる | いちばん大きい | 使わない側に合わせた設計 |
| 消す | 中くらい | 何も残らない |
こう並べると迷う要素がありません。「整理する」と聞くと、きれいにまとめる作業を想像しがちですが、いちばん効果があったのは消すことでした。
消す前に確かめた3つのこと
とはいえ、動いているものを消すのは怖い作業です。「消していいかどうかを先に確かめてから消して」と頼み、次の3つを順番に見てもらいました。
1. 新しく作られる経路が、本当にないか
画面から消したつもりでも、別の入口が残っていることがあります。データを保存している箇所をすべて洗ってもらい、古い形式で保存する処理がどこにも残っていないことを確認しました。「もう使っていないはず」ではなく、書き込む場所が1つもないと言い切れる状態です。
2. 本番のデータに、該当するものが何件あるか
本番のデータベースを直接数えてもらいました。結果は0件です。ここが1件でもあれば、話はまったく変わります。数えずに「たぶんない」で進めていたら、次の項目で書く事故がそのまま起きていました。
3. 消したあと、そのデータはどう扱われるのか
これがいちばん重要でした。そして、私の指示には入っていませんでした。挙げてきたのはAIのほうです。
3つのうち、私が頼んだのは前の2つだけです。3つめと、次に書く判定の細かい話は、作業を進めるなかでAI側から出てきました。実際に検討されたことを並べると、こうなります。
分岐を消した瞬間、全員への再送が有効になった
ここからが、この連載でいちばん怖かった話です。消す作業そのものが、送信のスイッチを入れかけました。
古い処理は、配信の本流にある枝分かれだった
古いA/Bテストの処理は、配信の本流のなかに「もしA/Bテストなら、こちら」という枝分かれとして置かれていました。機能を消すなら、この枝分かれも消します。消すと、当然ながら分岐がなくなり、すべてが通常の配信として扱われます。
分岐がなくなると、古いデータが通常配信として拾われる
ここで何が起きるか。過去にA/Bテストとして作られた配信のデータが、もし1件でも残っていたら、それは「まだ送っていない通常の配信」として拾われます。そして読者全員に送られます。何か月も前に一度終わったはずの配信が、ある日突然、全員の受信箱に届く。
▼
「A/Bテストの印が付いているか?」
├ 付いている → A/Bテスト用の処理へ(一部の人にだけ送る)
└ 付いていない → 通常の配信として全員へ
▼
判定する場所がなくなる
▼
印が付いた古いデータも、通常の配信として全員へ
▼
拾う段階で、印が付いたデータを対象から外す
▼
古いデータは、そこに残ったまま何も起こさない
拾う段階で外す条件を、分岐の削除と同時に足した
今回は0件だったので、実際には何も起きません。ですが、これは運がよかっただけです。「該当データが0件だから消してよい」と「消しても安全な作りにする」は別の話でした。
なので、分岐を消すのと同時に、古い形式のデータは配信の対象から外すという条件を入れてもらいました。処理される前に、拾う段階で除外します。手動で送信ボタンを押した場合も同じく止まります。古いデータは、そこに残ったまま何も起こさない状態になります。
| やったこと | 理由 |
|---|---|
| 古い処理そのものを削除 | 使う経路がもうない |
| 拾う段階で古いデータを除外 | 分岐がなくなると通常配信として全員へ送られる |
| 手動の送信ボタンでも止める | 自動と手動で入口が2つあるため |
「空欄」の意味が、データベースとプログラムで違った
もうひとつ、細かいところがありました。「この項目が空かどうか」という判定は、データベース側とプログラム側の両方に書く必要があるのですが、この2つは空の定義が違います。データベースの設定によっては、空欄と、スペースが1つだけ入った状態を、同じものとして扱います。プログラム側は別物として扱います。
スペースが1つだけ → 空
スペースが1つだけ → 空ではない
この書き分けは、私の指示には一言も入っていません。実装したAIが最初からそう書いていて、理由を読むまで、こんな落とし穴があるとは想像もしていませんでした。
消したもの、残したもの
削除といっても、全部を消したわけではありません。動かす仕組みと、残っている記録は分けて考えました。
動かす仕組みだけ消して、記録は残した
全部消したわけではありません。データを保存する場所そのものと、過去の結果を管理画面で見る部分は残しました。
理由は単純で、過去にやったテストの結果を見られなくなるのが嫌だったからです。動かす仕組みは要らないけれど、記録は読めるようにしておく。つまり、この2つは分けて考えられます。
| 対象 | 判断 |
|---|---|
| 動かす仕組み(773行) | 削除 |
| 保存されているデータ | 残す |
| 過去の結果を表示する画面 | 残す |
確認は、動かして22項目。やらせたのはAI
確認は、実際に動かして16項目です。通常の配信がきちんと送られること。古い形式のデータが自動でも手動でも動かないこと。空欄の判定がずれるパターンでも除外されること。あわせて、過去の結果を見る画面が壊れていないことを6項目。動かして確かめる作業もAIにやらせ、そのうえで、書いた側とは別のAIに監査させました。私がやったのは、確認してほしい項目を伝えることと、結果を読むことです。
削除のほうが、追加より確認が多かった
削除は、追加より確認が少なくて済むと思っていました。しかし、実際は逆でした。追加したものは動かせば分かりますが、消したものは「起きないこと」を確かめる必要があります。起きないことを確認するには、起きる条件をこちらで作らないといけません。
よくある質問
同じ判断を自社のシステムでするときに、迷いそうなところを4つ挙げます。
Q1. 使っていない機能でも、残しておくほうが安全では
残すこと自体は無料ではありません。周りに手を入れるたび、その部分も壊れていないか確かめる対象に入ります。今回のように、まったく別の作業をした拍子に動き出す可能性も残ります。
私の基準は、「今後これを使う具体的な予定があるか」です。予定がなく、記録として見たいだけなら、動かす部分だけ消して記録は残せます。
Q2. なぜ最初から1つに作れなかったのですか
作れませんでした。最初は、A/Bテストがどれくらいの仕事量なのか分かっていなかったからです。おまけの設定で足りると思って作り、使ってみて足りないと分かりました。
これは失敗というより、順序の問題だと思っています。ただし、作り直したその日に古いほうを消していれば、この回の話は発生しませんでした。反省があるとすれば設計ではなく、片付けを後回しにしたことのほうです。
Q3. AIに「使っていないコードを消して」と頼めば済みませんか
頼めば消してくれますし、消す作業自体も速いです。問題は、消したあとにどう振る舞うかの判断で、これは私が決めることでした。
「この分岐を消すと、古い形式のデータはどこにも当てはまらなくなります。どう扱いますか」。「空欄のときの判定が、2つの実装で食い違っています。どちらに揃えますか」。どちらも、実装と検査を進めるなかでAIのほうから出てきた質問です。ただ、そこで古いデータを配信対象から外して残すと決めたのは私です。データごと消してしまう手もありましたし、記録を残す価値がないなら、そちらのほうが簡単でした。何を残したいかは、作った本人しか知りません。
Q4. 自社のシステムで同じことを判断するには
機能そのものではなく、データが何件あるかを聞いてみてください。「もう使っていない機能ですが、過去のデータは何件残っていますか」という質問です。
0件なら、たいてい消せます。残っているなら、消したあとにそのデータがどう扱われるかを必ず確認します。宙に浮いたデータが、別の処理に拾われるというのが今回の要点でした。
ばんのの視点:使っていない機能ほど、消す日に事故が起きる
今回の話は、システムの話に見えて、実は棚卸しの話でした。経営側で使える形に直して2つ書きます。
止まっているのではなく、動き出す条件を待っている
今回いちばん覚えておきたいのは、使っていない機能は、置いてあるだけでは止まっていない、ということです。周りを触った日に動き出します。
動いていないものは何もしない、と考えがちです。実際には、周りが変わった瞬間に動き出す可能性を持ったまま、そこに座っています。私の場合、古い機能を消すという作業そのものが引き金になりかけました。触らなければ安全で、触ったら危ないのではなく、触るきっかけがいつか必ず来るということです。
この構図はシステムに限りません。使っていない業務フロー、誰も回していないチェックシート、退職者のアカウント。どれも「あるだけ」に見えて、条件が揃うと動きます。棚卸しというのは、本来こういうものを見つける作業なのだと思います。
増えた量ではなく、確かめる量が減ったかで見る
もうひとつ。私はこの1か月、機能を足すことばかりしていました。足すと画面が増えるので、進んだ感じがします。今回は773行減って、画面は1つも増えていません。それでも、この回がいちばん効果がありました。
増やした量ではなく、確かめないといけない量が減ったかどうか。自社のシステムを見るときも、この見方のほうが役に立つと思っています。
次回予告
次回、第8回で最終回です。
第1回で、月額数千円のサービスを使わずに自分で作ることにした理由を3つ挙げました。新しいドメインで一から設置し直しになること。AIを使った開発を覚えたかったこと。どうせなら自分の運用に合わせたかったこと。
その3つに、いまの時点で答えを出します。実際にかかった時間、AIに任せた仕事と自分がやった仕事の分かれ目、そして既製品を使うべき人と自分で作るべき人の線引き。手放しで勧める話にはならないと思います。