コメント
まだコメントはありません。
まだコメントはありません。
このブログのコードベースを一気に修正しました。デプロイスクリプトの堅牢化、セキュリティヘッダーの追加、lintエラー・警告の全消し、1,000行超あった管理コンソールの分割、コンポーネント全体のアトミックデザイン再編まで。
この記事は「何をしたか」ではなく、壊さないために何に気をつけたかのメモです。大きな変更ほど、進め方のルールが品質を決めます。
管理画面の分割では、ロジックの書き換えと構造の変更を同時にやらないと決めました。状態とハンドラはフックへ、表示はパネルコンポーネントへ「コピーして移す」だけ。気の利いた書き換えをしたくなっても我慢します。
差分レビューで「行が移動しただけ」と分かる形を保てば、レビューコストも退行リスクも一気に下がります。改善したい箇所はメモして、移植が終わってから別の変更として行います。
一番怖いのは、黙って失敗する処理です。
• デプロイは wrangler versions deploy の後に deployments list --json を読み、新バージョンが100%トラフィックで有効かを確認。確認できなければ例外で停止
• バージョンIDの抽出はCLIのテキスト出力に依存しすぎないよう、JSON出力へのフォールバックを用意
• Turnstileのサイトキー未設定も、画面の警告表示だけでなくサーバー/クライアント両方でログを出す
「成功したように見えて、実は古いバージョンが動いている」が最悪のパターンなので、確認できないことは失敗として扱います。
静的解析が「SQLの MAX(likes - 1, 0) は未定義動作」と報告してきましたが、SQLiteの max() は2引数以上ならスカラー関数で、正規の挙動です。ほかにも "id" in mail のプロパティ存在チェックをバグと誤認した報告がありました。
誤検知を「修正」すると、それ自体が本物のバグになります。直す前に必ず一次情報(公式ドキュメント・実際のコード)で検証する。これはAIに調査させたときほど大事です。
Reactの setState-in-effect 警告は、setTimeoutで包んで黙らせることもできますが、それでは警告の意図(マウント直後のカスケード描画の防止)が消えません。マウント判定やlocalStorage読み取りは useSyncExternalStore で「外部ストアの購読」としてモデリングし直しました。
どうしても意図的に残す例外(認証後のフルリロードなど)は、理由をコメントで書いた上で1行だけdisable。「なぜ例外なのか」が残っていれば、次に触る人が判断できます。
D1のマイグレーションは forward-only で、down マイグレーションの仕組みがありません。スキーマを触る変更には、先にロールバックSQLと手順書を用意しました。バックアップ手段の確認も先です。
canaryバージョンへの依存も同じ発想で、exact pin + 更新手順の文書化によって「戻せる単位」にしています。進む前に、戻れることを確認する。
format / typecheck / lint / 91本のユニットテスト / 管理機能の構造カバレッジ / 広告設定の監査 / 実サーバーでのE2E(ログイン→記事作成→公開→削除)を、変更のたびに全部回しました。
このブログには「ソースのパスと内容パターンを直接検証する構造テスト」があるので、ファイルを移動するとテストが落ちます。面倒に見えますが、テストの追従までがリファクタリングです。人間の「たぶん大丈夫」は信用しません。
• 挙動を変えない(移植に徹する)
• 黙って失敗させない(fail-loud)
• ツールも自分も疑う(一次情報で検証)
• 戻り道を先に作る(ロールバック・pin)
この4つを守れば、大きな変更でも怖くありません。逆に言うと、これを守らない「ついでの改善」が一番事故ります。
Turnstile site key が未設定のため、このフォームは送信できません。管理者は NEXT_PUBLIC_TURNSTILE_SITE_KEY を設定してください。