家を建ててから見えてくるもの
自分が作ったサイトを、他人の目で見る方法
unstackd.ioがオンラインに上がった。
ドメインをつなぎ、ネームサーバーを変え、ブラウザにアドレスを打った。見慣れた画面が出た。ヒーロースローガン、タイムライン、フッター。全部あった。気分が良かった。
ところが気分が良いことと、ちゃんとできていることは別の問題だった。
サイトを一つの「製品」として見て、四人の専門家の目で点検してみた。シニアウェブ開発者、UI/UXデザイナー、セキュリティ専門家、サービス開発者。もちろん四人ともAIだ。しかしそれぞれの視点から出た指摘は本物だった。
結果は予想より長かった。
一つ目の指摘:ignoreBuildErrors: true。
これは私が数週間前に、ビルドエラーが出るたびにつけた設定だ。「エラーがあってもとりあえずビルドしろ。」プログラミングを知らない人間の論理では合理的だった。エラーが出るとサイトが表示されず、サイトが表示されなければ進まないから、とりあえず表示してから考えよう。
問題は——これがシートベルトを切って運転するのと同じだったということだ。
TypeScriptというのはコードで型が合っているか検査する道具だ。「この変数は数字であるべきです」と定めておくと、うっかり文字列を入れたときにビルド段階で警告をくれる。その警告を全部無視するという設定をオンにしていたのだ。
直すのに10個のコミットが必要だった。
二つ目の指摘:セキュリティ。
管理者APIに入力検証がなかった。どういう意味かというと——誰かがサーバーにデータを送るとき、送るべきフィールド(「タイトル」「内容」「状態」といったもの)以外に、任意のフィールドを紛れ込ませることができたという意味だ。
一人運営のサイトにハッカーが来る確率は低い。しかし「確率が低い」は「やらなくていい」という意味ではない。
ホワイトリストというものを作った。許可されたフィールドの一覧をあらかじめ定めておき、一覧にないものは全部捨てる。コードではこう見える:
const ALLOWED_FIELDS = ['title_ko', 'title_ja', 'title_en', 'desc_ko', ...];
function sanitizeBody(body) {
return Object.fromEntries(
Object.entries(body).filter(([key]) => ALLOWED_FIELDS.includes(key))
);
}
一行も自分で書いていない。AIが書いた。私がしたのは「こういうセキュリティ脆弱性があるから直せ」と指示したことだけだ。
三つ目はちょっと恥ずかしい問題だった。
ホームページの下に巨大な空白があった。エントリーが9個しかないのに、スクロールをずいぶん下げないとフッターが出なかった。原因を探ると二つあった。ヒーロー領域に「最小の高さ75%」がかかっていて、コンテンツ領域に「残りの空間を全部埋めろ」という属性がついていた。
作るときは分からなかった。「こうすればきれいに出るだろう」と思って入れた属性が、エントリーが少ないときに空白を作り出した。完成してから見えるもの。
そして最も混乱した問題:Git構造。
プロジェクトフォルダの中に.gitが二つあった。ルートに一つ、site/の中に一つ。両方とも同じGitHubリポジトリを指していたが、それぞれ別の時点のコードを追跡していた。ある修正はsite/site/パスに適用され、あるものはsite/に適用されていた。
これは最初にプロジェクトを作るとき、構造をきちんと立てなかったために生じた問題だ。Episode 02で「計画がコードより先だ」と学んだのに、そのときの教訓がここでも繰り返されたのだ。
今日site/.gitを削除し、重複ファイルを整理した。以前のバージョンのプロトタイプ3個、完了した作業指示書3個、複製された文書7個、空のフォルダ、キャッシュファイル。全部合わせると二十を超える不要なファイルがプロジェクトに溜まっていた。
この過程で気づいたことが一つある。
作ることは興奮する仕事だ。機能を追加し、画面に何かが現れ、デプロイボタンを押せば世に公開される。これには達成感がある。
しかし点検することは退屈な仕事だ。型エラーの修正、セキュリティ検証、空白の除去、フォルダの整理。これは新しいものを作るのではなく、すでに作ったものを整える仕事だ。画面に見える変化がないときもある。
夜しか時間がない人にとって、この退屈な時間を別に確保するのは難しい。限られた時間で新しい機能をもう一つ作りたい誘惑がある。
だからこれをルールにすることにした。 新しい機能を三つ作ったら、一度は点検の時間を持つ。 3:1のルール。
家を建てたなら、たまには屋根を見上げなければならない。
🔧 このエピソードの技術用語解説
ignoreBuildErrors Next.jsの設定で、TypeScriptの型エラーがあってもビルドを強制的に通過させるオプション。開発初期には便利だが、デプロイ段階ではランタイムエラーをビルド時点で捕まえられなくする危険な設定。
入力検証 / ホワイトリスト(Input Validation / Whitelist) サーバーが外部から受け取るデータを検査する手続き。ホワイトリストは「許可されたものだけ通す」方式。反対はブラックリスト(禁止されたものだけ遮断)だが、セキュリティではホワイトリストの方が安全だ。
Git(.git)
コードのバージョン管理システム。すべての変更履歴を記録する。.gitフォルダがプロジェクト内に二つあると、二つの独立した履歴が衝突する。
flex-1 / min-h
CSS(ウェブスタイリング言語)の属性。flex-1は「余った空間を全部占めろ」、min-hは「最低でもこの高さは保て」という意味。コンテンツが少ないとき、意図しない空白を作ることがある。
コミット(Commit) コードの変更を一つの単位として保存する行為。「この時点のコードの状態を記録する」という意味。10個のコミットは10回の意味ある変更があったという意味だ。