お前がコードを書き始める前に
言っておきたい事がある
かなりきびしい話もするが
俺の本音を聞いておけ
はじめに
これから少しの間、不器用で、偉そうで、厳しいことを言う。けれど最後まで聞いてくれれば、その裏側にあるものもわかってもらえると思う。だから先に謝っておく。生意気な口を、許してほしい。
まず、お前に話す前に、業界を取り巻く空気の話をさせてくれ。ソフトウェア業界には、昔から消えない風潮がある。
「売れたプロダクトはすべて正しい」
「品質? 障害が起きなければそれでいい」
「細かいことはベンダーに丸投げで構わない」
ビジネスの現場で生き抜くための割り切りとしては、わからなくもない。けれど、エンジニアの職業倫理からすると、これはやはり、許しがたい。家は崩れなければ中身はどうでもいいという建築家がいたとする。その建築家が立てた家に、あなたは住みたいだろうか?
そこへ来て、生成AIによる「バイブコーディング」の波である。
「IT素人の私が、たった1週間で◯◯アプリを作りました!」
「これまで100時間かかっていた仕事が、たった5時間で自動化できました!」
その驚きは、悪くない。素晴らしいことだ。エンジニアリングの楽しさへの、最高の入口だ。Xでシェアするのも、誰かに自慢するのも、大いにやっていい。
ただし、そのレベルのものを、絶対に、本番リリースするな。
ビジネスサイドの気持ちもわかる。誰でもソフトウェアが書けるようになったこの千載一遇のチャンスを、活かしたくないわけがない。チャンスを潰したくもない。
だからこの記事は、その両方のバランスを取るための、最低限のガイドラインだ。
第一条 セキュリティだけは、絶対に守れ
お前が作ったアプリで、誰かのクレジットカード情報が漏れたとする。誰かのプライベートな写真が流出したとする。そのとき「すみません、AIが書いたコードだったので」は、通用しない。法廷でも、Xでも、自分の良心の前でも、通用しない。
セキュリティだけは、譲るな。譲れない。
IaaS には、まだ手を出すな
AWS、GCP、Azure を生で触るのはやめておけ。これらはプロ向けの工具箱だ。便利だが、使い方を間違えると指が飛ぶ。
- S3バケットを「全世界に公開」のまま放置して個人情報を流出させた事例は、毎年のように繰り返されている
- セキュリティグループを 0.0.0.0/0 で開けっぱなしにして、翌朝マイニング業者にサーバーを乗っ取られていた話も枚挙にいとまがない
- IAMロールの設定を一つ間違えるだけで、本番DBが全部抜かれることもある
IaaSを使っていいのは、その罠を知り尽くしている人間だけだ。「知り尽くしている」というのは、「AWS Well-Architectedの基本を理解し、セキュリティグループ・IAM・ネットワーク設計の罠を自分の言葉で説明できる」くらいの意味だと思ってくれていい。
PaaS も、まだ早い
「じゃあ Vercel や Firebase なら大丈夫?」 ——残念ながら、まだ早い。
たとえば Firestore のセキュリティルールは、テストモードを選ぶとデフォルトで全許可に近い状態から始まる。そのままリリースすると、URLを少し変えるだけで他人のデータが丸見えになる。Supabase の Row Level Security も同じだ。「ログインできる」と「他人のデータを見られない」は、まったく別の問題なのだ。
IaaSと比べれば、PaaSの方が注意すべきことはずっと減る。だが、それでも PaaS が提供するセキュリティガイドラインなどを読み込み、何度か実験用アプリを構築して、そのサービスの罠を検証した上で使った方がよい。それができないなら、まだやめておいた方がいい。
Lovable や Bolt のような SaaS型ビルダーに頼れ
じゃあどうしろと。——答えは、Lovable や Bolt.new のような、もっと上のレイヤーのSaaSに頼ること。これらは認証、DB、ホスティングまで含めて「とりあえず安全側に倒した既定値」を提供してくれる。
ただし、SaaSにも罠はある。
- 公開設定・共有設定を必ず確認すること
- 連携した外部サービス(OpenAI APIキーなど)の権限と上限を確認すること
- 「誰がアクセスできるか」を、自分の言葉で説明できる状態にしておくこと
それができないなら、まだリリースするな。
シークレットと鍵を、コードに書くな
SaaSレイヤーを使っていても、シークレット管理まで魔法のように解決してくれるわけではない。ここを雑にやると、結局いちばん危ない。
- APIキー、秘密鍵、トークンは、コードやプロンプトに直書きするな。SaaSが用意している Secrets や環境変数の仕組みに入れろ
- ブラウザに置いてよい公開鍵と、サーバー側だけに置く秘密鍵を混同するな。公開してよいものと、漏れたら終わるものは別物だ
- 権限は最小にしろ。使わないAPIまで叩ける万能キーを作るな
- テスト用と本番用で鍵を分けろ。同じ鍵を使い回すな
- 漏えいを前提に、再発行と無効化の手順を先に確認しておけ。鍵は、いつか漏れるものだと思え
- エラーログ、画面キャプチャ、AIへの質問文に鍵を貼るな。漏れるときは、だいたいそこから漏れる
「SaaSだから安全」の意味は、「お前の代わりに秘密を管理してくれる」ではない。秘密をどこに置き、誰が触れて、漏れたらどう止めるかは、最後までお前の責任だ。
「ログインできる」と「他人のデータが見えない」は、別物だ
ログイン機能を実装できたとき、人は「セキュリティができた」と勘違いする。違う。それは入口の鍵をつけただけだ。中に入った人が、他人の部屋を覗けるかどうかは、まったく別の話なのだ。
具体的に言おう。お前が https://myapp.com/orders/12345 というURLで自分の注文を見られるとする。では、12345 を 12346 に変えたら、他人の注文が見えてしまわないか? これを IDOR (Insecure Direct Object Reference) と呼ぶ。OWASP の脆弱性ランキングでも常に上位にいる、典型的な事故の一つだ。
防ぐ作法は、たった一つ。
データを取り出すたびに、「これは本当に今ログインしているユーザーのものか?」をサーバー側でチェックする
「URLにIDが入ってるんだから、本人しか見ないでしょ」という性善説は、通じない。AIに「注文を取得するAPIを書いて」と頼むと、平気でこのチェックを忘れたコードを返してくる。レビューしろ。必ず。
入力は、すべて疑え
ユーザーが入力した値、外部APIから返ってきたデータ、アップロードされたファイル ——これらはすべて「敵かもしれない」と思って扱え。性善説は、Webの世界では命取りだ。
「フォームでバリデーションしてるから大丈夫」は、通じない。
ブラウザ上のチェック(クライアントサイドバリデーション)は、あくまでUXのための補助だ。セキュリティの盾にはならない。ブラウザの開発者ツールを開けば、誰でも数秒でJavaScriptを無効化したり、HTTPリクエストを直接書き換えたりできる。「年齢は18歳以上のみ」「数値しか入力できない」「100文字以内」——そういった制約は、クライアントでいくら設けても、サーバー側で同じチェックをしていなければ意味がない。バリデーションは、必ずサーバー側でも行え。
特にファイルアップロードは事故の宝庫だ。
- 拡張子だけを見て「画像だ」と判断する → 中身は実行可能ファイルだった
- ファイル名をそのまま保存先パスに使う →
../../etc/passwdのような相対パスで脱出される(パストラバーサル) - サイズ上限を設けない → 100GBのファイルをアップロードされてディスクが埋まる
- SVG画像をそのまま表示する → 中にJavaScriptが仕込まれていてXSS
「とりあえずアップロード機能をつけたい」なら、SaaS型ビルダーが用意した既定の仕組みに乗るのが一番安全だ。自前で実装するな。
AIが提案するライブラリを、鵜呑みにするな
「このライブラリを使えばできます」とAIは平気で言う。だがそのライブラリ、本当に信用してよいのか? 最終更新はいつだ? メンテナーは誰だ?
実際、AIは存在しないライブラリ名を堂々と提案してくることがある(ハルシネーション)。あるいは、5年前にメンテが止まった脆弱性だらけのパッケージを推してくることもある。最悪のケースでは、攻撃者が「AIがよく間違えるパッケージ名」を悪用して悪意あるコードをアップロードしている事例まである(タイポスクワッティング)。
ライブラリを入れる前に、最低これだけはやれ。
- 公式リポジトリ(npm、PyPI等)で実在を確認する
- 最終更新が直近1年以内か確認する
- GitHubのスター数、Issue数、メンテナの活動を見る
- ライセンスを確認する(GPL系を商用で使うと面倒なことになる)
-
package-lock.jsonやrequirements.txtでバージョンを固定する
依存ライブラリは、お前のアプリの「外注先」だ。素性の知れない外注先には、仕事を出すな。
エラーメッセージで、内部情報を漏らすな
AIが書くコードは、エラーが起きたときにエラー情報(スタックトレース)をそのままユーザーに返すことが多い。これも事故だ。
- DBのテーブル名・カラム名
- 内部のファイルパス
- 使っているライブラリのバージョン
- SQL文そのもの
これらは攻撃者にとっての地図になる。本番環境では、ユーザーには「処理に失敗しました」程度の抽象的なメッセージだけを返し、詳細はサーバー側のログにだけ残せ。「開発モード」と「本番モード」を切り替えるだけで対処できるフレームワークがほとんどだから、最初に確認しておけ。
「社内システムだから大丈夫」は、幻想だ
社内向けのアプリを作っているのなら、こう思っているかもしれない。「外部に公開していないから、セキュリティはそこまで気にしなくていいでしょ」と。
その考えが、事故の引き金になる。
理由は4つだ。
- 内部が一番危ない: 漏洩の原因は外部攻撃より内部持ち出しやマルウェア感染が多い。退職者のアカウントが残ったままになっていた、なんて話は珍しくない
- 社内ネットワークはもう安全地帯ではない: テレワーク・BYOD・クラウドの普及で「内側=安全」は崩れた。ゼロトラストとは「内外を問わず全アクセスを疑え」という考え方で、まさにこの前提から生まれた
- 踏み台にされる: 攻撃者はセキュリティの甘い社内システムを足がかりに、本番へ**横移動(ラテラルムーブメント)**する。「大した情報がない」は関係ない。侵入口になること自体が被害だ
- 気づかないまま漏れ続ける: 社内システムはインシデントの検知が遅れる。数ヶ月、数年にわたって流出し続けていた事例も実在する
補足 — 会社が許可していないAIツールを、勝手に使うな
まずAIに関係なく、当たり前の話をする。会社がそのAIツールを採用していない、そのMCPの利用を許可していない——それにはたぶん理由がある。自分が個人で契約しているサービスの方が賢いと思っても、会社が決めたルールの外へ出るな。それは「どちらが便利か」の問題ではなく、超えてはいけない一線だ。なぜ当たり前のことをわざわざ言うかというと、今のIT部門はAIに対して特に神経質になっているからだ。同じシャドーITでも、AIの場合は反応が段違いに厳しい。
社内業務でAIコーディングツールを使うなら、最低限以下を意識しておけ。
- 会社が承認したアカウント・ツールを使え: 私用アカウントで社内業務をするな。IT部門が把握していないサービスに、社内の情報を流すな
- 何を貼り付けるかを確認しろ、チャット履歴は外部サーバーに残る: 機密コード、顧客データ、APIキー、エラーログは貼るな。学習されないから大丈夫ではない。社外のサーバーに記録が残り続けるリスクを忘れるな
ログを残し、定期的に見ろ
セキュリティ対策を施しても、それだけでは足りない。何が起きたかを記録し、定期的に確認する仕組みがなければ、侵害されていることにすら気づけない。
現実はこうだ。
- サーバーに不正アクセスされ、数週間にわたって内部を探索されていたのに、ログを誰も見ていないまま放置されていた
- ユーザーデータが少しずつ抜き出されていた
- 自分のサーバーがマルウェアの踏み台にされ、他社や他国への攻撃に加担していた ——知らぬ間に加害者になっていた
「自分のアプリは小さいから狙われない」は通じない。攻撃の多くは自動化されており、無差別にスキャンしてくる。脆弱なシステムを見つけたら、規模に関係なく使われる。
最低限、やっておくべきことはこれだ。
- アクセスログとエラーログを必ず残す: 誰がいつ何にアクセスしたか、異常なエラーが何件発生しているかを記録する
- ログの保存先を分ける: アプリサーバーだけにログを置くな。侵害されると同時に証拠も消える
- 定期的に目を通す: 週に一度でもいい。アクセス数の急増、見覚えのないIPからのアクセス、深夜の大量リクエストなど、いつもと違うパターンに気づく習慣をつけろ
- アラートを設定する: 異常を検知したら通知が来るようにする。自分でログを見に行く前に、システムが知らせてくれる状態にしておけ
- ログに機密情報を流すな: ログはCloudWatchやDatadog、Sentryなど外部SaaSに送られることが多い。パスワード、APIキー、クレジットカード番号、個人情報(氏名・メール・住所)は出すな。あとから消すのが一番難しいデータだ。最初から書かないのが唯一の正解
ログは、事後にしか役に立たない。だからこそ、何も起きていないうちから残しておくしかない。「事件が起きてから記録しておけばよかった」では、手遅れだ。
第二条 コストは、事前に見積り、後で必ず確認しろ。確認は1回じゃない、定期的にだ
お前が寝ている間に、クラウドの請求は跳ねる。
- LLM APIを無限ループで叩き続けて、一晩で数十万円
- Firestoreの読み取り課金を理解せず、トップページを開くたびに数千回の読み取りが走る設計
- 画像生成APIを「ユーザーが押すたびに」呼び出す設計で、悪意あるユーザーに連打される
コードを書く前に、料金体系を理解しろ
「使ったぶんだけ払う」モデルは、事前に使用量を見積もらないと青天井になる。実装を始める前に最低これだけ確認しておけ。
- 課金単位を把握する: リクエスト数か、トークン数か、読み取り回数か、ストレージ量か。単価と無料枠を公式ドキュメントで確認する
- ユーザー数とリクエスト頻度を仮定して計算する: 「1日100人が10回使ったら月いくら?」を手を動かして試算する
- ハードリミットを設定できるサービスを選ぶ: 上限を超えたら強制停止できるか。できないサービスは、使うリスクを理解した上で選べ
- 無料枠の落とし穴を確認する: 無料期間終了後の価格、トライアルのクレジット切れ後の挙動を必ず読む
リリース後も、定期的に確認しろ
「最初に設定したから大丈夫」は通じない。使われ方が変われば、コストも変わる。
- 予算アラートを最初に設定する(これをやる前にコードを書くな)
- リリース後、請求ダッシュボードを見る: リリース直後は特に。異常な急増にその日のうちに気づける
- 週次・月次でトレンドを見る: 毎日見てもよいが、じわじわ上がっているコストは、日次では気づきにくい
「動いた!」と喜んでいるその裏で、メーターは回っている。回り続けている。
第三条 法的にOKかどうか、最初に確認しろ
コードを書き始める前に、5分でいい、考えてくれ。
- そのデータをスクレイピングしていいのか(利用規約)
- 個人情報を扱うのか(個人情報保護法、GDPR)
- そのライブラリのライセンスは商用利用OKか(GPL汚染)
- AIが生成した画像・文章の著作権リスクは
- 医療・金融・法律など、業法規制のある領域に踏み込んでいないか
「知らなかった」は、法律の前では言い訳にならない。損害賠償で済めばまだいいが、刑法犯や行政罰だとそれだけでは済まない。
第四条 「そのアプリは、使い捨てか?」を自問せよ
ここから先は、使い捨てではないアプリを作る人だけ読めばいい。
週末に自分用に作って、月曜には捨てるアプリなら、ここまでで読むのをやめてもいい。だが、誰かに使ってもらう、明日も動かす、来月も動かす ——そういうアプリなら、ここからが本番だ。
コードは変えられても、データ構造はそう簡単には変えられない
これは、ソフトウェア開発における最も重要な真実の一つだ。覚えておいてほしい。
コードのバグは直せる。
データ構造の負債は、後から払うと、利息がついて返ってくる。
具体的にはこういうことだ。
- スキーマ変更は破壊的になりがち: 一度ユーザーデータが入ったテーブルにカラムを変更したり、型を変えたりするのは、新規にテーブルを作るのとは比べ物にならないほど難しい
- マイグレーションには順序がある: 「コードを先にデプロイする」「DBを先に変更する」「両対応の中間状態を経由する」など、ダウンタイムなしで変えるには定石がある
- 本番DBは、必ずバックアップを取ってから触れ: 取り返しのつかないことが、本当に、起きる
だから、コードを書き始める前に、データ設計で以下を確認しておけ。
- 何を「エンティティ」として持つかを言語化する: 「ユーザー」「注文」「商品」など、アプリが扱う概念を洗い出せ。AIに「テーブル設計して」と頼む前に、自分の言葉で説明できるようにしておけ
- 関係性を整理する: 「ユーザーは複数の注文を持てるか」「注文には複数の商品が入れられるか」——この1対多・多対多の関係を把握していないと、後からテーブルを根本から作り直す羽目になる
- 変わりやすい項目を特定する: 「この属性、将来増える可能性はないか」「選択肢が固定でないなら、別テーブルにすべきでは」——後から型や構造を変えるコストを、設計段階でイメージしておけ
- 削除をどう扱うかを決める: レコードを本当に消すのか(物理削除)、削除フラグを立てるだけにするのか(論理削除)。後から変えると影響範囲が広い。最初に決めておけ
- AIが作ったテーブル構造を、そのまま放置するな: AIが勝手にテーブルを作った場合も、「どんなテーブルが、どんな構造で作られているか」を自分の目で確認しろ。AIは「動くもの」を素早く出すのは得意だが、「将来変えやすい設計」を優先するとは限らない
もし後からデータ構造を変える必要が出たら最低限、以下を守れ。
- 本番DBには自動バックアップを設定する(これは、なんにしろ最初にやっとけ)
- マイグレーションは必ずステージング環境で試してから本番に適用する: ステージングで通っても安心するな。本番には本番固有のデータが入っている。ドライランを実行して、想定外のレコードや制約違反がないかを事前に確認しろ。また、カラム名の変更・型の変更・カラムの削除といった「既存のコードが壊れる変更」をする場合は、サービスを一時停止してから適用しろ。無停止でやる方法も存在するが、それは熟練者向けの話だ。ユーザーへの告知をして潔く止め、終わったら再起動する——それが一番リスクが低い
- 本番データは直接触るな: コンソールやSQLクライアントで本番データベースを直接操作するな。データ操作は必ずテスト済みのコード(マイグレーションスクリプトやバッチプログラム)を経由して実行しろ。また、操作が想定どおり完了したことを確実に検証できる手段——件数確認、チェックサム比較、ログの突き合わせなど——をあらかじめ準備しておけ。さらに、実行前のバックアップと、問題が起きたときのリストアのリハーサルまでを「セット」として整備しておけ。リストアを実際に試したことがない復旧手順は、存在しないのと同じだ
「途中で落ちたら、どうなる?」を常に考えろ
これも、AIが書くコードに頻出する事故だ。
決済処理を例にしよう。「ユーザーの残高を引く」「商品の在庫を減らす」「注文レコードを作る」——この3つのうち、2つ目で停電が起きたら、何が起きる? お金は引かれたのに、商品は届かない。
これを防ぐ概念が二つある。
- トランザクション境界: 「ここからここまでは、全部成功するか、全部なかったことにするか、どちらかにする」という宣言。
- 冪等性 (Idempotency): 「同じ処理を何回実行しても、結果が同じになる」性質。ネットワークが切れて再送されても、二重課金にならないようにするための盾
「同じボタンを2回連打されたら、二重に注文が入る」「決済APIがタイムアウトして、リトライしたら二重に課金された」 ——こういう事故は、この二つを意識していないと必ず起きる。AIに処理を書かせたら、「これ、途中で落ちたらどうなる?」「2回呼ばれたらどうなる?」と必ず聞き返せ。
AIに意味のあるテストを書かせるには、観点を指示しろ
AIは「テストを書いて」と言えば、とりあえず生成する。だがハッピーパスしか書かない、あるいは網羅的なテストを書かせようとするとモックを多用して意味のないテストをすることがある。意味のあるテストにするには、丸なげするよりは、ステップを分けて確認した方がよい。
- 「今回の実装した部分の仕様書を作ってください」
- 仕様書の網羅性を確認する。疑問があれば聞く
- 「この仕様書から網羅的なテストケースを洗い出した上で、自動テストでカバーすべき範囲、人的に確認すべき範囲を精査してドキュメントにまとめてください」
- ドキュメントを確認する。疑問があれば聞く
- 「自動テストでカバーすべき範囲を実装し、ドキュメントに実装状況を記載してください」
- 実装されたことを確認する。だいたい単体テストしか自動化してくれないので、次に結合テストを指示する
- 「仕様書を確認し、結合してテストした方がよいテストケースを洗い出して、ドキュメントを更新してください」
- 結合テストのケースを確認する
- 「結合テストを実装し、ドキュメントに実装状況を記載してください」
- 意味的につながりのある機能についてはAIが判断できないので、追加で指摘する
- 「◯◯の処理をした後に、✗✗をしたらどうなりますか?テストしてますか?」
- :
AIが書いたテストは、必ず自分で読め。テストはドキュメントだ。読めないなら、AIにテスト項目を説明させろ。
-
テスト名が仕様になっているか:
test_1ではなく「注文金額が0円のときは注文を拒否する」 - Arrange / Act / Assert が明確か: 準備・実行・検証が分離されているか
- モックが多すぎないか: モックだらけのテストは「コードがモックを呼んだか」しか確認していない
- テストが実装の詳細に依存していないか: 内部の変数名やプライベートメソッドをテストしているなら、リファクタリングのたびにテストが壊れる
保守性は、未来の自分への手紙だ
3週間後の自分は、他人だ。3ヶ月後の自分は、もっと他人だ。
- DRY (Don't Repeat Yourself): 同じロジックを2箇所以上に書くな。直し漏れの温床になる
- 仕様を理解しろ: AIが書いたコードでも、自分の言葉で「これは何をしているコードか」を説明できる状態にしておけ
- 説明できないものはリリースするな: これは厳しいようでいて、結局は自分を守るルールだ
構成管理(Git)を、必ず使え
「昨日まで動いていたのに、今日動かない」——これを救ってくれるのは Git だけだ。Lovable や Bolt のようなSaaSレイヤーを使っていても、ここに例外はない。
- 小さく、頻繁にコミットする
- コミットメッセージには「何を」「なぜ」変えたかを書く
-
.gitignoreでシークレット(APIキー、環境変数ファイル)を絶対にコミットしない - GitHubリポジトリは、最初は必ずプライベートにする
これだけで、開発の安心感が10倍変わる。
開発環境と本番環境を、分けろ
これは譲るな。「本番でちょっと試す」が事故の99%だ。
- 開発環境(自分のPC)
- ステージング環境(本番と同じ構成のテスト用)
- 本番環境(ユーザーが使う場所)
最低でも「開発」と「本番」は分けろ。データベースも別にしろ。「うっかり本番のユーザーデータを全部消した」は、笑い話にならない。
第五条 性能を、見積もれ
そのアプリ、何人が使う? データは何件入る? 1日に何回叩かれる?
- ユーザーが10人なら、富豪的な実装でいい
- ユーザーが1万人になった瞬間、ループ内DB問い合わせ(N+1問題)はサーバーを溶かす
- データが100万件を超えると、インデックスのない検索は数十秒かかるようになる
最初から完璧に作る必要はない。ただ、「いま自分が書いているコードは、何件まで耐えられる設計か」を、ぼんやりとでいいから把握しておけ。それだけで、事故の半分は防げる。
第六条 失敗から学べ。だがその前に、先人の失敗を学んでおけ
最後に、これが一番大事かもしれない。
ソフトウェアエンジニアリングという分野は、半世紀以上にわたって、無数の失敗と、その失敗から学んだ知恵を蓄積してきた。バージョン管理、テスト、CI/CD、コードレビュー、設計パターン、SRE、セキュリティのベストプラクティス ——これらはすべて、誰かが痛い目を見ながら積み上げてきた知恵だ。
お前が同じ失敗を繰り返す必要はない。
事前に書籍や、インシデントの事例から学ぶこともできる。
全部読めとは言わない。気になったところだけでいい。だが、先人がすでに転んだ穴に、自分も律儀に落ちる必要はないのだ。
それでも、失敗をすることはある。
そのとき、どう対処するかが重要だ。
- まず止める: 被害を広げるな。アプリを止め、APIキーを無効化し、影響範囲を最小にする。「まず確認してから」と迷っている間に、被害は広がる
- 何が起きたかを記録する: 発生時刻、検知した経緯、その時点でわかっていること。記憶は劣化するが、記録は残る。後の原因調査と再発防止に必ず使う
- 影響を受けた人に早く知らせる: 「まだわからないので調査中です」でいい。黙っていることの方が、信頼を失う。何も言わないのが最悪だ
- 原因を突き止める: 表面の症状ではなく、「なぜそれが起きたか」を掘れ。「個人のミス」で終わらせるな。なぜそのミスが起きる状況があったのかを問え
- 再発策を仕組みで作る: まずは類似の問題が起きないよう、テストを見直す・アラートを見直すなど、構造で防げ。ただし、仕組みだけでは応用が効かない。それと並行して、失敗の原因を抽象化して捉え、「いつ・何を・どう注意すべきか」を自分の言葉で説明できるようにしておけ。そして、それを記録しておくのがよい
失敗そのものより、失敗の後に何をするかの方が、長期的にはずっと大事だ。
付録 ― AIに聞くための観点インデックス
これは読み物ではない。AIに質問を投げるための「索引」 だ。
この知識がなくても、作れないことはない。
だが、こういった観点があると、AIが出した結果やプログラムが動いた結果を見たときに、何を見て、どう対処すべきかが分かる。
以下は、プロの観点を、AIに質問するためのキーワードとして並べたものだ。使い方はこうだ。
- 作っているものに関係しそうな章を眺める
- 知らない用語、気になる用語を見つける
- AIに「○○について、初心者にもわかるように教えて」と聞く
全部を理解する必要はない。今日のお前に必要な2〜3項目だけ拾えばいい。明日になったら、また別の2〜3項目が必要になる。そうやって少しずつ、自分の武器を増やしていってほしい。
大分類一覧
設計レビューで見ている観点
- A. アーキテクチャ設計
- B. データとインターフェース
- C. UX設計
- D. 非機能・運用
- E. セキュリティ設計
コードレビューで見ている観点
- F. UI設計・フロントエンド
- G. 設計原則とパターン
- H. コード品質
- I. テスト
- J. 実装技術
- K. プロセスとドキュメント
- L. セキュアコーディング
- M. 参考書籍・フレームワーク
設計レビューで見ている観点(クリックで展開)
A. アーキテクチャ設計
A-1. アーキテクチャスタイル
- レイヤードアーキテクチャ
- ヘキサゴナルアーキテクチャ(Ports and Adapters)
- オニオンアーキテクチャ
- クリーンアーキテクチャ
- マイクロサービス vs モノリス vs モジュラーモノリス
- イベント駆動アーキテクチャ(EDA)
- CQRS(Command Query Responsibility Segregation)
- イベントソーシング
- BFF(Backend for Frontend)
- サーバーレスアーキテクチャ
A-2. ドメインモデリング
- DDD(ドメイン駆動設計)
- 境界づけられたコンテキスト(Bounded Context)
- ユビキタス言語
- エンティティ / 値オブジェクト / 集約(Aggregate)
- ドメインイベント
- 戦略的設計 vs 戦術的設計
- コンテキストマップ
A-3. モジュール分割・依存関係
- 高凝集・低結合(High Cohesion, Low Coupling)
- 依存性逆転の原則(Dependency Inversion)
- 循環依存の排除
- パッケージ原則(REP/CCP/CRP、ADP/SDP/SAP)
- 依存方向の統制
- 安定度・抽象度のバランス
B. データとインターフェース
B-1. データモデリング
- 正規化と非正規化のトレードオフ
- ERモデリング
- スタースキーマ / スノーフレークスキーマ
- イミュータブルデータモデル
- Event Sourcing による履歴保持
- Single Source of Truth
B-2. API設計
- REST原則(統一インターフェース、ステートレス)
- リソース指向設計
- GraphQL vs REST vs gRPC
- バージョニング戦略(URLパス、ヘッダ、メディアタイプ)
- ページネーション(オフセット型、カーソル型)
- HATEOAS
- OpenAPI / Swagger仕様
- 冪等性キー(Idempotency Key)ヘッダ
- エラーレスポンス設計(RFC 7807 Problem Details)
B-3. 整合性・トランザクション
- トランザクション境界の設計
- ACID特性
- DB整合性制約(主キー、外部キー、ユニーク、CHECK)
- 楽観ロック vs 悲観ロック
- 分散トランザクション
- Sagaパターン
- 結果整合性(Eventual Consistency)
- 冪等性(Idempotency)
- Outboxパターン
- グレースフルシャットダウン
B-4. 非同期処理(Queue/Event)
- At-least-once / At-most-once / Exactly-once delivery
- Dead Letter Queue(DLQ)
- idempotency key による重複排除
- Outboxパターン(トランザクショナルメッセージング)
- キューの優先度分離とフェアシェア
- Visibility Timeout
- Pub/Sub vs メッセージキュー
B-5. キャッシュ
- キャッシュ一貫性モデル(Strong/Eventual Consistency)
- cache-aside / write-through / write-back パターン
- キャッシュスタンピード(Thundering Herd)対策
- TTL jitter
- ホットキー問題
- CDNエッジキャッシュ
- マルチレイヤーキャッシュ
C. UX設計
C-1. ユーザーリサーチ
- ペルソナ
- カスタマージャーニーマップ
- ユーザーインタビュー
- エスノグラフィ調査
- Jobs to Be Done(JTBD)
- メンタルモデル
- ユーザビリティテスト
- A/Bテスト
- 定量調査 vs 定性調査
C-2. 情報設計(Information Architecture)
- サイトマップ
- カードソーティング
- ナビゲーション設計(グローバル/ローカル/コンテキスト)
- パンくずリスト
- ファセット検索
- 情報の階層と粒度
- メンタルモデルとの整合
C-3. インタラクション設計
- ユーザーフロー / タスクフロー
- ワイヤーフレーム
- プロトタイピング(低忠実度 / 高忠実度)
- マイクロインタラクション
- フィードバック設計(即時性・可視性)
- エラー防止・エラーリカバリー
- Undo / Redo
- オンボーディング設計
- 空状態(Empty State)設計
C-4. UX原則・ヒューリスティクス
- ニールセンの10ユーザビリティヒューリスティクス
- ドナルド・ノーマンの『誰のためのデザイン?』
- アフォーダンス / シグニファイア
- 認知負荷(Cognitive Load)
- ヒックの法則
- フィッツの法則
- ミラーの法則(7±2)
- ヤコブの法則
- ピーク・エンドの法則
- ゲシュタルト原則
C-5. アクセシビリティ(UX側)
- WCAG(Web Content Accessibility Guidelines)
- WAI-ARIA
- インクルーシブデザイン
- ユニバーサルデザイン
- スクリーンリーダー対応
- キーボード操作対応
- 色覚多様性への配慮
- 認知アクセシビリティ
C-6. UXメトリクス
- HEART フレームワーク(Happiness、Engagement、Adoption、Retention、Task Success)
- NPS(Net Promoter Score)
- CSAT(Customer Satisfaction)
- SUS(System Usability Scale)
- タスク成功率 / 離脱率
- Time on Task
D. 非機能・運用
D-1. スケーラビリティ
- 水平スケーリング vs 垂直スケーリング
- ステートレス設計
- データシャーディング
- レプリケーション(Leader-Follower、Multi-Leader)
- CAP定理
- PACELC定理
- ロードバランシング戦略
D-2. 可用性・レジリエンス
- 単一障害点(SPOF:Single Point of Failure)
- サーキットブレーカーパターン
- バルクヘッドパターン
- 指数バックオフとリトライ
- カナリアリリース / Blue-Greenデプロイ / フィーチャーフラグ
- ヘルスチェックと自動復旧
- カオスエンジニアリング
- RTO / RPO(目標復旧時間・目標復旧時点)
D-3. 可観測性(Observability)
- 3本柱:ログ、メトリクス、トレース
- 分散トレーシング(OpenTelemetry)
- 構造化ログ(Structured Logging)
- SLI / SLO / SLA
- ゴールデンシグナル(レイテンシ、トラフィック、エラー、飽和度)
- アラート疲れとアラート設計
D-4. 環境・インフラ設計
- 本番/ステージング/開発環境の分離
- Infrastructure as Code(Terraform、Pulumi、CloudFormation)
- 12 Factor App
- コンテナオーケストレーション(Kubernetes)
- GitOps
- サービスメッシュ
D-5. データマイグレーション
- expand-migrate-contractパターン
- 冪等なマイグレーションスクリプト
- ロールバック戦略
- データ整合性検証(件数比較、チェックサム)
- 段階的移行 vs メンテナンスウィンドウ
- Zero-downtime deployment
E. セキュリティ設計
E-1. セキュリティ原則
- Defense in Depth(多層防御)
- 侵害前提の設計(Assume Breach)
- ゼロトラスト(Zero Trust)
- 最小権限の原則(Principle of Least Privilege)
- デフォルト拒否(Deny by Default)
- 監査証跡(Audit Trail)
E-2. データ保護・マルチテナント
- データ分類(機密/内部/公開)
- マルチテナントのテナント隔離
- クラウドのセキュリティベースライン(AWS Well-Architected、Azure Security Benchmark)
E-3. LLMセキュリティ
- プロンプトインジェクション(直接・間接)
- ツール汚染(Tool Poisoning)/ 過剰なエージェント権限
- LLM入出力の通信経路・データ保持・学習利用の把握
- 学習・監視・保持からのオプトアウト設定の確認
- LLM出力の信頼境界(出力を無検証で実行しない)
- OWASP LLM Top 10
コードレビューで見ている観点(クリックで展開)
F. UI設計・フロントエンド
F-1. ビジュアルデザイン原則
- タイポグラフィ(フォント階層、可読性、行間)
- カラー理論(配色、コントラスト比、カラーパレット)
- 余白(ホワイトスペース)と密度
- グリッドシステム(8ptグリッド、12カラム)
- 視覚的階層(Visual Hierarchy)
- 近接・整列・反復・コントラスト(CRAP原則)
- スキューモーフィズム vs フラットデザイン vs ニューモーフィズム
- マテリアルデザイン / Human Interface Guidelines / Fluent Design
F-2. デザインシステム
- デザイントークン(色、余白、タイポグラフィ)
- アトミックデザイン(Atoms / Molecules / Organisms / Templates / Pages)
- コンポーネントライブラリ(Storybook、Figma)
- 命名規則(BEM、SMACSS)
- ブランドガイドライン
- Figma / Sketch / Adobe XD 等のデザインツール連携
F-3. コンポーネント設計
- Presentational Component vs Container Component
- Compound Component パターン
- Render Props / Higher-Order Component
- Controlled vs Uncontrolled Component
- Composition vs Configuration(合成性)
- Slot / Children パターン
- Props drilling と Context / State管理
F-4. スタイリング
- CSS Modules
- CSS-in-JS(styled-components、Emotion)
- Utility-First(Tailwind CSS)
- CSS設計手法(BEM、SMACSS、OOCSS、FLOCSS)
- CSS Variables(カスタムプロパティ)
- レスポンシブデザイン(ブレークポイント、モバイルファースト)
- Container Queries
- ダークモード対応
F-5. 状態管理
- ローカル状態 vs グローバル状態
- Redux / Zustand / Jotai / Recoil
- React Context
- サーバー状態(TanStack Query、SWR)
- フォーム状態(React Hook Form、Formik)
- URL状態(クエリパラメータ)
- 楽観的更新(Optimistic Update)
F-6. フロントエンドパフォーマンス
- Core Web Vitals(LCP、FID/INP、CLS)
- コード分割(Code Splitting)
- 遅延読み込み(Lazy Loading)
- Tree Shaking
- バンドルサイズ最適化
- 画像最適化(WebP、AVIF、next/image)
- 仮想スクロール(Virtual Scrolling)
- メモ化(React.memo、useMemo、useCallback)
- SSR / SSG / ISR / CSR
F-7. アクセシビリティ(実装側)
- セマンティックHTML
- ARIA属性の適切な使用
- フォーカス管理(フォーカストラップ、フォーカスリング)
- キーボードナビゲーション
- スクリーンリーダー対応テスト
- コントラスト比の確保
- フォームのラベル付け
- ライブリージョン(aria-live)
F-8. アニメーション・インタラクション
- CSS Transitions / Animations
- JavaScript アニメーションライブラリ(Framer Motion、GSAP)
- イージング関数
- パフォーマンスを意識したアニメーション(transform、opacity)
- prefers-reduced-motion への対応
- スケルトンスクリーン
- ローディング状態の表現
G. 設計原則とパターン
G-1. 設計原則
- SOLID原則
- SRP(単一責任の原則)
- OCP(開放閉鎖の原則)
- LSP(リスコフの置換原則)
- ISP(インターフェース分離の原則)
- DIP(依存性逆転の原則)
- DRY(Don't Repeat Yourself)
- KISS(Keep It Simple, Stupid)
- YAGNI(You Aren't Gonna Need It)
- 関心の分離(Separation of Concerns)
- 最小驚きの原則(Principle of Least Astonishment)
- Tell, Don't Ask
- Law of Demeter(デメテルの法則)
- Command-Query Separation(CQS)
- Composition over Inheritance
- Fail Fast
G-2. デザインパターン(GoF)
- 生成:Factory Method、Abstract Factory、Builder、Singleton、Prototype
- 構造:Adapter、Bridge、Composite、Decorator、Facade、Flyweight、Proxy
- 振る舞い:Chain of Responsibility、Command、Iterator、Mediator、Observer、State、Strategy、Template Method、Visitor
G-3. エンタープライズパターン(PoEAA等)
- Repository パターン
- Unit of Work
- Data Mapper vs Active Record
- Service Layer
- Domain Model vs Transaction Script
- Specification パターン
- Null Object パターン
H. コード品質
H-1. クリーンコード
- 意味のある命名(変数、関数、クラス)
- 関数は1つのことだけをする
- 関数の引数は少なく(理想は0〜2個)
- 副作用の最小化
- コメントは「なぜ」を書き、「何を」はコードで表現
- マジックナンバー・マジックストリングの排除
- ネストの深さを浅く保つ(早期リターン)
- ブール引数フラグの排除
H-2. リファクタリング
- コードの臭い(Code Smell)
- 長すぎるメソッド / 巨大クラス
- 機能の横恋慕(Feature Envy)
- データの群れ(Data Clumps)
- 散弾銃的変更(Shotgun Surgery)
- 神クラス(God Class)
- プリミティブ型への執着(Primitive Obsession)
- メソッドの抽出(Extract Method)
- クラスの抽出(Extract Class)
- 変数のインライン化 / 導入
- ポリモーフィズムによる条件分岐の置き換え
- ガード節の導入
H-3. 型設計・契約
- 型駆動設計(Type-Driven Development)
- Make Illegal States Unrepresentable
- 値オブジェクト(Value Object)による型安全性
- Null安全(Option/Maybe、Nullable参照型)
- 不変性(Immutability)
- 事前条件・事後条件・不変条件(Design by Contract)
- パーシング vs バリデーション("Parse, don't validate")
H-4. 関数型プログラミングの考え方
- 純粋関数
- 参照透過性
- 副作用の分離
- 高階関数
- イミュータブルデータ構造
- map / filter / reduce
- モナド(Option、Either、Result)
H-5. エラーハンドリング
- 例外 vs Result型の使い分け
- Checked Exception vs Unchecked Exception
- 例外の握りつぶし禁止
- 早期リターン・ガード節
- Fail Fast原則
- リカバリー可能エラー vs 回復不能エラー
- 指数バックオフ with jitter
- リトライすべき処理としてはいけない処理の区別
I. テスト
I-1. テスト戦略・哲学
- テストピラミッド(Mike Cohn)
- テスティングトロフィー(Kent C. Dodds)
- テストダイヤモンド / ハニカム
- テスト駆動開発(TDD)
- Red-Green-Refactor
- Given-When-Then / Arrange-Act-Assert
- BDD(Behavior-Driven Development)
- テストカバレッジの罠(カバレッジ100%≠バグゼロ)
- Flaky テスト対策
- 早すぎるモック / モックの使いすぎ問題
I-2. テストの種類(機能)
- ユニットテスト(Jest、Vitest、JUnit、pytest)
- 統合テスト(Integration Test)
- E2Eテスト(Playwright、Cypress、Selenium)
- コンポーネントテスト(Testing Library)
- インタラクションテスト(Storybook Interaction Tests、user-event)
- スナップショットテスト
- プロパティベーステスト(fast-check、Hypothesis、QuickCheck)
- ミューテーションテスト(Stryker、PIT)
- スモークテスト
- 回帰テスト(Regression Test)
- 受け入れテスト(Acceptance Test)
- 探索的テスト(Exploratory Testing)
I-3. テストの種類(UI・ビジュアル)
- Visual Regression Test(Chromatic、Percy、reg-suit、Playwright視覚比較)
- アクセシビリティテスト(axe-core、Lighthouse、pa11y)
- クロスブラウザテスト(BrowserStack、Sauce Labs)
- レスポンシブテスト
- スクリーンショットテスト
I-4. テストの種類(契約・境界)
- コントラクトテスト(Pact、Spring Cloud Contract)
- Consumer-Driven Contract Testing
- APIテスト(Postman、REST Assured、supertest)
- スキーマテスト(JSON Schema、OpenAPI検証)
I-5. テストの種類(非機能)
- 負荷テスト(Load Test)
- ストレステスト(Stress Test)
- スパイクテスト
- 耐久テスト(Soak Test / Endurance Test)
- パフォーマンステスト(k6、JMeter、Gatling、Locust)
- セキュリティテスト(SAST、DAST、IAST)
- ペネトレーションテスト
- カオステスト(Chaos Monkey、Litmus)
- ファジングテスト(Fuzzing)
I-6. テストダブル
- Dummy
- Stub
- Spy
- Mock
- Fake
- Test Double の使い分け(Gerard Meszaros)
I-7. テスト設計技法
- 同値分割
- 境界値分析
- デシジョンテーブル
- 状態遷移テスト
- ペアワイズテスト
J. 実装技術
J-1. 並行処理・マルチスレッド
- スレッドセーフティ
- 不変オブジェクト(Immutable)による安全性
- ConcurrentHashMap、AtomicInteger等のスレッドセーフコレクション
- レースコンディション
- TOCTOU(Time Of Check To Time Of Use)
- デッドロック対策(ロック順序統一、tryLock)
- ExecutorServiceとスレッドプール上限
- async/await パターン
- Reactive Programming
J-2. パフォーマンス
- N+1問題
- インデックス設計
- EXPLAIN によるクエリプラン分析
- Big O記法・計算量
- メモリリーク
- プロファイリング
- 早すぎる最適化を避ける(Premature Optimization)
- キャッシュ戦略
- バッチ処理 vs ストリーム処理
- コネクションプール(接続数の上限設定・解放漏れ)
- スロークエリログの分析
-
SELECT *の回避(必要なカラムだけ取得する) - ページネーション性能(オフセット型は件数増加で劣化する)
- 非同期・並列処理の適切な活用
- バックプレッシャー(処理速度の差を吸収する仕組み)
- コールドスタート問題(サーバーレス特有)
- データ転送量の最適化(over-fetching / under-fetching)
- レスポンス圧縮(gzip / Brotli)
- Keep-Alive とコネクション再利用
- CDN の適切な活用
K. プロセスとドキュメント
K-1. ドキュメンテーション
- ADR(Architecture Decision Record)
- READMEの書き方
- APIドキュメント(OpenAPI、JSDoc、Javadoc)
- 図の描き分け(C4モデル、UML、シーケンス図)
- 自己文書化コード
K-2. バージョン管理・開発プロセス
- Gitのコミット粒度
- Conventional Commits
- ブランチ戦略(Git Flow、GitHub Flow、Trunk-Based Development)
- プルリクエストのレビュー作法
- セマンティックバージョニング(SemVer)
- CI/CDパイプライン
- フィーチャーフラグ
L. セキュアコーディング
L-1. 脅威モデリング
- STRIDE(Spoofing/Tampering/Repudiation/Information Disclosure/DoS/Elevation of Privilege)
- NIST攻撃者分類
- Attack Surface Analysis
- 信頼境界(Trust Boundary)
L-2. 通信の保護
- TLS 1.2以上、弱い暗号スイートの無効化
- 証明書ピンニング、ホスト名検証
- HSTS(HTTP Strict Transport Security)
- Content-Security-Policy(CSP)
- X-Frame-Options / frame-ancestors
- X-Content-Type-Options: nosniff
- Referrer-Policy
- CORS設定(
*とcredentialsの組み合わせ禁止)
L-3. 暗号化・機密情報
- CRYPTREC暗号リスト
- CSPRNG(暗号論的擬似乱数生成器)
- bcrypt / Argon2 / scrypt
- ソルトとストレッチング
- IV(初期化ベクトル)のランダム化
- KMS / HSM / Vault / Secrets Manager
- 鍵ローテーション
L-4. 認証・セッション
- Authorization Code Flow + PKCE
- OIDCのstate / nonce / redirect_uri検証
- アクセストークン/リフレッシュトークンの回転
- MFA(TOTP、WebAuthn、FIDO2)
- パスワードスプレー攻撃、Credential Stuffing対策
- レート制限とアカウントロック
- Cookie属性(Secure / HttpOnly / SameSite)
- Session Fixation対策(ログイン時のID再生成)
- JWTの
exp、jti、機密情報非格納 - セッション強制失効(ログアウト、パスワード変更時)
L-5. 認可・アクセス制御
- サーバサイドでの権限検証
- IDOR(Insecure Direct Object Reference)対策
- テナント境界チェック
- スコープ(scope)ベースの権限管理
- RBAC / ABAC
- 403 Forbidden vs 404 Not Found の使い分け
L-6. 入力検証
- ホワイトリスト方式
- JSON Schema / OpenAPI でのスキーマ検証
- NULLバイト・制御文字の拒否
- XMLのXXE(XML External Entity)対策
- Billion Laughs攻撃対策
- ファイルアップロード:拡張子・MIME・マジックナンバーの三点判定
- パストラバーサル(Path Traversal)対策
- Zip Bomb対策
- SVGのサニタイズ
- CSV Injection(Formula Injection)
L-7. インジェクション攻撃
- SQLインジェクションとプリペアドステートメント
- ORMのRawクエリのリスク
- OSコマンドインジェクションと引数配列形式
- LDAPインジェクション
- NoSQLインジェクション
- テンプレートインジェクション(SSTI)
- デシリアライズ攻撃(Java Serialization、pickle、fastjson)
L-8. 出力エンコーディング
- コンテキスト別エスケープ(HTML/属性/JavaScript/URL/CSS)
- React
dangerouslySetInnerHTMLのリスク - Angular
[innerHTML]のリスク -
javascript:/data:スキームの拒否 - HTTPヘッダインジェクション(CRLF Injection)
- オープンリダイレクト対策
L-9. エラー処理(セキュリティ観点)
- 本番環境でのスタックトレース非表示
- 一般化されたエラーメッセージ
- 機密情報をログに出さない
L-10. SSRF(サーバサイドリクエストフォージェリ)
- ホワイトリストベースのURL検証
- DNS解決後のIP検証
- CNAMEチェーン追跡
- リンクローカルアドレス(169.254.169.254)のブロック
- クラウドメタデータサービスへのアクセス遮断
- IMDSv2(AWS)
- DNS Rebinding対策
- 自動リダイレクトの無効化
L-11. 依存関係
- lockファイル(package-lock.json、requirements.txt、Gemfile.lock)
- 脆弱性スキャン(Dependabot、Snyk、Trivy)
- タイポスクワッティング攻撃
- サプライチェーン攻撃
- ライセンス互換性(GPL、MIT、Apache 2.0)
- EOL(End of Life)パッケージの置換
- SBOM(Software Bill of Materials)
M. 参考書籍・フレームワーク
M-1. 設計・実装全般
- 『Clean Architecture』『Clean Code』(Robert C. Martin)
- 『リファクタリング』(Martin Fowler)
- 『エリック・エヴァンスのドメイン駆動設計』
- 『実装パターン』(Kent Beck)
- 『エンタープライズアプリケーションアーキテクチャパターン(PoEAA)』
- 『達人プログラマー』
- 『リーダブルコード』
M-2. セキュリティ
- OWASP Top 10
- OWASP ASVS(Application Security Verification Standard)
- OWASP Testing Guide
- IPA「安全なウェブサイトの作り方」
- CERT Secure Coding Standards
- CWE(Common Weakness Enumeration)
この索引は、お前が成長するにつれて少しずつ意味を持ち始める。最初は呪文の羅列にしか見えないかもしれないが、ある日「あ、これが今ぶつかっている問題だ」と気づく瞬間が必ず来る。そのときに戻ってくればいい。
おわりに ― それでも、お前の挑戦を応援している
ここまで、ずいぶん厳しいことを書いた。
「素人は引っ込んでろ」と言っているように聞こえたかもしれない。違う。まったく違う。
私はこの仕事を20年やってきた。その間に、自分でも数えきれないほどの失敗をしてきたし、先輩や同僚や、時には後輩が悲惨な目に合うのを目にしてきた。1週間以上24時間体制で障害復旧をしたこと、1つの障害の再発防止策に3年かかったこと、お客様に頭を下げに行くためだけに9時間新幹線に乗ったこと——どれも、流血沙汰ではないが、ちょっとした流血よりもはるかに有害なストレスを伴う。
私は、いま起きている変化を、手放しで「ソフトウェアの民主化」とは呼びたくない。開発の利権や主導権は、むしろAIプラットフォーマーに強く握られようとしているし、その意味では本当の意味で民主化されたとは到底言えない。
それでも、重要な変化は間違いなく起きている。本当に課題を持った人が、自分の手でソフトウェアを書き、自分の現場の問題を、自分の言葉で試行錯誤しながら形にできるようになったことだ。私はそこに、これまでよりもずっと切実で、具体的で、価値のあるソフトウェアが生まれる可能性を見ている。
だからこそ、その入口で躓いてほしくない。
「バイブコーディングで作ったアプリで、個人情報を流出させてしまった」
「請求書を見たら、自分の3か月分の給料が消えていた」
「楽しかった開発が、訴訟と賠償で終わった」
そして私がもう一つ強く懸念しているのは、AI驚き屋や、AI活用煽り屋に釣られて、ろくに責任も品質も考えていないふざけたサービスが世の中に量産されることだ。そういうものが増えれば増えるほど、傷つくのはユーザーであり、下がるのはソフトウェア全体への信頼だ。
ソフトウェアは無形資産であり、目に見えない部分も多く、信頼でなりたっている。その信頼を失ったら終わりだ。
ただ萎縮して慎重になれと言いたいわけではない。むしろ、致命的な失敗だけは避けながら、仮説を立て、試し、壊し、学び、また直すことを、何度でも繰り返してほしい。それがエンジニアリングの基本だからだ。
その先には、本物のエンジニアリングの世界が広がっている。そこには、半世紀以上かけて積み上げられた知恵と、先人たちの失敗の記録と、それを次の誰かに手渡そうとする無数の人たちがいる。
わからないことがあったら、身近なプロに聞いてほしい。
AIに聞く場合は、自分が確信を持って責任をとれるというレベルまで裏を取ってほしい。
お前の作ったアプリが、いつか誰かを本当に助ける日のために。
そのときに胸を張って「私が作りました」と言えるように。
最低限の作法だけは、守ってほしい。
それが、ソフトウェアという長い長い営みに、新しく加わるお前への、先輩からの ——少し不器用な——歓迎の言葉だ。
ようこそ、こちら側へ。
