本番に一度でも書いたら終わる。だから書けない複製を作った
Kimiのkimi-for-codingで執筆しました
読み取り権限だけ渡された本番SaaSがある。
顧客が毎日ぶん回している、業務の心臓みたいなやつ。 それを「勉強も兼ねて自分の手元でクローンする」というPoCをやっている。
で、この手の作業でいちばん怖いのは何かというと。
間違えて本番に書き込むことです。
参照系のつもりで叩いたAPIが、実は更新系だった。 ドラッグ&ドロップの「見るだけ」のつもりが、離した瞬間に本番へcommitされていた。 配車表を一枚いじったら、明日の現場が動く。
想像しただけで発狂しませんか。 自分はします。
「本番に書かない」を「気をつける」で守るのは無理
最初に落とした結論はこれです。
人間の注意力で「本番に書き込まないよう気をつける」は、遅かれ早かれ破れる。 眠いとき、急いでるとき、「たぶん参照系だろう」と思ったとき。事故は全部そこから出る。
だから方針を、願いから仕組みに変えました。
- 観察は見るだけ。本番はブラウザで開いても、書き込みトリガ(ドロップ=確定)は絶対に踏まない。ネットワークのログを見て「どのAPIがどんな形を返すか」だけ持ち帰る。
- 手元のデータに本物を残さない。クローンが使うサンプルデータは、本物を機械的に別の値へ置換した合成物(=フェイク)だけ。人名も車番も電話番号も、リポジトリには一文字も入れない。
- そして極めつけが、次の一個。
約束じゃなくてテストで縛る(egress-fence)
クローンの書き込み処理には、「外に一通信も出さない」ことを検証するテストを置きました。
やってることは単純で。 書き込みの処理を走らせる直前に、外向き通信の入口(fetchとかhttpとか)を全部、呼ばれたら即エラーになる罠に差し替える。 その状態で保存処理を動かして、「ちゃんとローカルに保存できて、かつ罠は一度も踏んでいない」ことを確認する。
もし将来、誰かがうっかり本番へ通信するコードを足したら。 このテストが真っ赤になって、そもそもcommitが通らない。
ここが肝で。
「本番に書かない」は、開発者の善意ではなく、落ちるテストで守る。
善意はレビューを通り抜けます。 赤いテストは通り抜けません。 信じるべきは前者じゃなくて後者、という話です。
そもそも「本番に書き込むアダプタ」を一行も実装しない、という選択もしています。 書き込み先はローカルのDB一択で、本番へ書く経路は「存在しない」。 存在しない機能はバグらない。いちばん強い防壁は、コードが無いことでした。
ついでに「嘘をつかない」も仕組みにした
クローンなので、当然ながら本物と挙動が違う箇所が出ます。 ここで雑にやると、「それっぽく動くけど本物とは別物」という一番たちの悪いやつが生まれる。
なので、本物とわざと変えた点は、全部理由つきの台帳に一行ずつ書く。 「まだ観察してないから」「実データが0%だから作らない」「捏造できないから空欄で保全」区分まで決めて記録する。 台帳に無い「こっそり乖離」はルール違反。
観察してから実装する。 見てないものは作らない。想像で埋めない。 地味だけど、これをやるかどうかで、クローンが「資料」になるか「それっぽい嘘」になるかが分かれます。
今回いじったのは「行が湧いてこない表」
具体のエピソードをひとつ。
配車の割り当てを並べる表があって。 クローンの初期版は、行(=車両やドライバー)を「割り当て済みの案件から逆算して」出していました。 つまり、仕事が入ってない車は表に出てこない。ラクな実装だけど、本物とは違う。
本物は逆で、マスタ(台帳)を正として、仕事ゼロの空車も一行として並ぶ。 「今日ヒマな車、どれ?」が見える。これがそもそも配車表の存在意義だったりする。
で今回、その「マスタ」という別のデータ源をクローンに足して、表の行をマスタ由来に切り替えました。 軸も分けた。車両で並べる画面と、ドライバーで並べる画面。 面白かったのは、マージの規則をどうするか。 マスタに載ってる全員を行にしつつ、「マスタに居ないのに割り当てだけ在る」案件も、末尾に孤児行として必ず残す。
一件も落とさない。 データを消して画面をきれいにするのは、クローンでは嘘つきと同じなので。
「気をつける」はやめて、無い機能に全部預けた
読み取りしか許されない本番を相手にクローンを作るなら。
守りたいことは、気をつけるんじゃなくて、テストにする。 本物と違う点は、隠すんじゃなくて、理由つきで台帳に書く。 そして、いちばん危ない機能は作らないのが最強の防壁。
書き込みアダプタを実装しなかったから、自分は今日も本番を壊していません。 無いものは、壊せない。