1. 「スケールしたら対応する」の嘘
ソフトウェア開発でもっともよく聞く先送りの言葉がある。「スケールしたら対応する」。
この言葉が発せられた瞬間、ほぼ確実に、その対応は行われない。
理由は単純だ。スケールしたとき、開発者はスケールに伴う別の問題に追われている。ユーザー対応、バグ修正、機能要望。「あのとき先送りにした技術的負債」は、優先度リストの下に沈んでいく。そして本当に限界が来たとき、緊急対応として場当たり的なパッチが当てられる。
これが「場当たり的」の正体だ。先送りそのものが悪いのではない。先送りにした課題の「戻り方」を設計していないことが問題なのだ。
2. 場当たり的と移行設計の違い
場当たり的な対処と、移行経路の設計は、表面上は同じに見える。どちらも「今はやらない」という判断をしている。
違いは一点だけだ。
移行設計は、「今はやらないが、やるときに何を変えればよいか」が明確になっている。
具体的には、次の条件が揃っていることを指す。
- トリガーが定義されている——何が起きたら移行するのか
- 変更箇所が局所化されている——どこを変えればよいのか
- 手順が書かれている——どうやって移行するのか
この三つが揃っていれば、「今はやらない」は怠慢ではなく設計判断になる。
3. 一つの関数に集約する
TokiQRの運用では、Google Apps Script(GAS)からメールを送信している。GASの無料枠はGmail経由で1日100通。個人運営の初期段階では十分だが、注文が増えれば上限に達する。
将来的にはAmazon SES(Simple Email Service)に移行すれば、月62,000通が無料になる。だが今SESを組み込む必要はない。注文はまだ少ないし、AWSアカウントの設定やドメイン認証といったセットアップは、必要になってからで十分だ。
では何をしたか。メール送信のコードを一つの関数に集約した。
function sendEmail(recipient, subject, body, options) {
MailApp.sendEmail(recipient, subject, body, options || {});
}
コード全体で14箇所あったMailApp.sendEmailの直接呼び出しを、すべてこの関数経由に変えた。SESに移行するときは、この1関数の中身を書き換えるだけだ。
これは過剰設計ではない。関数一つ追加しただけだ。だがこの一つが、将来の移行コストを「14箇所の書き換え+テスト」から「1箇所の書き換え+テスト」に変える。
4. 三段階のロードマップ
メール送信だけでなく、TokiQRの運用全体も同じ原則で設計されている。
フェーズ1:自分で作る(現在)
印刷、UVラミネート加工、梱包、発送。すべて一人で行う。GASとGmailで運用は完結し、インフラコストはゼロ。1日50件程度まではこの体制で回る。
フェーズ2:国内外注
1日50件を超えたら、ラミネート生産を国内の印刷業者に委託する。GASから注文データを業者に連携し、印刷・加工・梱包・発送を一括で任せる。TokiStorage側は在庫ゼロ、作業ゼロの完全デジタル運営になる。メール送信はSESに移行。
フェーズ3:海外展開
海外注文が増えたら、顧客の国に応じて現地の生産拠点に振り分ける。注文データにはすでに国情報が含まれているので、ルーティングロジックの追加だけで対応できる。
各フェーズの移行で必要なコード変更は最小限だ。フェーズ2ではsendEmail関数の書き換えと業者連携の追加。フェーズ3では国別ルーティングの追加。いずれも既存のデータ構造を壊さない。
コードだけでは終わらない
フェーズの移行で変わるのは、コードだけではない。
生産を外注するということは、顧客の氏名と住所を第三者に渡すということだ。プライバシーポリシーに業務委託先への情報提供を明記し、特定商取引法の表記には引渡時期を外注先のリードタイムに合わせて更新する。利用規約のデータ取り扱いセクションも改訂が必要になる。
外注先との間ではNDA(秘密保持契約)を締結し、顧客情報の取り扱い範囲を定める。生産リードタイムや品質基準のSLA(サービスレベル合意)も取り決める。
これらは「スケールしたら考える」ではなく、今の段階で「何を更新する必要があるか」のリストとして手元に持っておく。移行設計の原則は、コードに限った話ではない。法務も、契約も、ポリシーも——変更が必要な箇所と手順を事前に書き出しておくことが、場当たり的にならないための条件だ。
お金の自動化は慎重に段階を踏む
TokiQRにはパートナー還元の仕組みがある。紹介経由の注文に対し、売上の10%をパートナーに支払う。現在は月次で自動集計し、Wiseの支払いリンク付きレポートを管理者に送信している。送金自体は手動だ。
パートナーが増えれば、この手動送金も移行対象になる。だがお金の自動化は、メールやファイルの自動化とは本質的に異なる。バグが即座に実害になる。
だから段階を刻む。まずはバッチCSVの自動生成。管理者がダウンロードし、Wiseにアップロードして一括送金する。金額を目視確認してからの実行なので、誤送金リスクがない。その次に、APIによる送金自動化。ただし金額上限を設け、超過時は承認待ちにする。
移行設計の原則はここでも同じだ。「今は手動でよい。だが次の段階で何をすればよいかは書いてある。」リスクの大きさに応じて段階の刻み方を変える——それも設計だ。
5. 過剰設計との境界
移行設計には、過剰設計に陥る誘惑がつきまとう。「将来のために」とあらゆるケースを想定し、使われない抽象化を積み重ねる。
その境界はどこにあるのか。
今の段階で動くコードに、一行も余計なものを足さない。
ただし、将来の変更が一箇所で済むように、責務を分離しておく。
sendEmail関数は、今この瞬間はMailApp.sendEmailをそのまま呼んでいるだけだ。ラッパーとしてのオーバーヘッドは実質ゼロ。だが将来の変更点を一箇所に局所化している。
これが「移行設計」と「過剰設計」の分水嶺だ。今の動作に一切影響を与えず、将来の移行コストだけを下げる。足すのは構造であって、機能ではない。
6. 継ぎ目のある設計
建築には「エキスパンションジョイント」という概念がある。地震や温度変化で建物が膨張・収縮したとき、構造全体が壊れないように設けられた継ぎ目だ。普段は何の役割も果たさない。だが力がかかったとき、その継ぎ目が建物を守る。
ソフトウェアにおけるマイグレーション設計も同じだ。関数の抽象化、データ構造の分離、設定の外出し。これらは平時には何もしない。だがフェーズが変わったとき、変更の衝撃を吸収する。
マイグレーションとは、巨大なシステムを事前に作ることではない。
小さな継ぎ目を、正しい場所に仕込んでおくことだ。
7. 場当たり的であることの本当のコスト
場当たり的な対処のコストは、技術的負債だけではない。
本当のコストは「判断の劣化」だ。緊急対応を繰り返すうちに、チームは「どうせまた急場しのぎになる」と学習する。設計への信頼が失われ、「ちゃんと作る」という選択肢が心理的に遠のく。
逆に、移行経路が設計されている組織では、「今はやらない」という判断に不安がない。やるときの手順が見えているから、安心して先送りにできる。先送りが罪悪感ではなく、優先順位の管理になる。
TokiQRでは、SES移行の手順書がgas/scaling-roadmap.mdに残されている。Lambda関数のコード、IAMロールの設定、GAS側の書き換え方法。すべてが書かれている。だから「今はやらない」と言える。やるときに何をすればよいか、わかっているからだ。
8. 個人開発におけるマイグレーション
この設計原則は、大規模なチーム開発だけのものではない。むしろ個人開発にこそ必要だ。
チームなら、誰かが技術的負債を覚えていてくれるかもしれない。だが個人開発では、3ヶ月前の自分が何を考えていたかすら忘れている。「スケールしたら対応する」と言った自分は、もういない。
だからこそ、移行経路をコードの近くに残す。手順書を書く。トリガー条件を明記する。未来の自分は他人だ。その他人が迷わず作業できるように、今の自分が道を敷いておく。
場当たり的とは、道がないことではない。
道があったことを、忘れてしまうことだ。