\n
日本AIセンター 社内教材
EV充電サービスを題材に、Web・データベース・AI駆動開発の土台を28ステップで体験する。基本・中級・上級のボタンで絞り込める。ボタンは全部押してよい。壊れたらリロードすれば直る。
学ぶ順序
基本=インターネットと画面の仕組み/中級=サービスを作る道具/上級=現場の事故と対策。STEP 26が総仕上げ。
STEP 0
これから触る全部の実験は、この3つの箱のどこかで起きている。まずこの地図だけ頭に入れる。
Webサービスの登場人物は3つしかない。あなたのスマホやPCで動くブラウザ(客席)、データセンターで動くサーバ(厨房)、そしてデータを保存するデータベース(冷蔵庫)。客席で「充電履歴を見せて」と注文すると、厨房が冷蔵庫から材料を出して料理し、完成した画面を客席に運ぶ。この往復がWebのすべてだ。
今回の題材は会員制のEV充電サービス。会員がアプリで充電し、履歴が記録され、料金が請求される。この教材で使う言葉づかい(Next.js・Prisma・PostgreSQL)は、実際の現場でそのまま使われている本物の道具の名前だ。
STEP 1
「/history」の「/」って何? の答え。URLは「建物の住所+部屋番号」でできていて、ページとは部屋そのもののこと。
URLはブラウザの上部に出ている、あの長い文字列だ。呪文に見えるが、実は郵便の宛名と同じ構造をしている。ドメイン=建物の住所(例:plugo.jp。世界に1つしかない)、パス=建物の中の部屋番号(例:/history。スラッシュで始まる部分)。そしてページとは、部屋の1つ1つのことだ。部屋に入ると1画面ぶんのHTML(画面の設計図)が出てくる。「充電履歴のページ」=「plugo.jpという建物の、/historyという部屋」。
ちなみにこの教材のURLにある「pages.dev」は、Cloudflare Pagesという「建物を貸してくれるサービス」の名前。自前の建物(独自ドメイン)を持たず、貸しビルの一室を借りている状態だ。
URLの分解
Q. https://plugo.jp/history の「建物」と「部屋」はそれぞれどこ?
建物=plugo.jp(ドメイン)、部屋=/history(パス)。https://は「渡し方のルール」(封をして安全に運ぶ約束)。
STEP 2
「plugo-like.jp」と打った0.1秒後、裏で何が起きているか。実はコンピュータは名前を理解できず、番号しか分からない。
コンピュータ同士はIPアドレスという番号(例:203.0.113.7)で相手を見つける。だがそんな番号は人間が覚えられないので、「名前→番号」を引ける世界規模の電話帳が用意されている。それがDNSだ。URLを開くたび、ブラウザはまずDNSに問い合わせて番号を手に入れてから、その番号に接続しに行く。
ログ
Q. DNSが止まると、サーバは元気でもサービスは開けなくなる。なぜ?
名前を番号に変換できないと、そもそもどこに接続すればいいか分からないから。住所録を失った郵便局と同じ状態になる。
STEP 3
ブラウザは常に「ください」とお願いしている。そのお願いの宛先に、人間用の窓口と機械用の窓口の2種類がある。機械用の窓口の名前がAPI。
URLを開くとき、裏では必ず「お願い」と「返事」の往復が起きている。お願いをリクエスト、返事をレスポンスと呼ぶ。お願いには種類があり、代表は2つ:GET=「見せて」(取得)、POST=「これを受け取って」(送信・作成)。
そして重要なのが、同じ建物の中に窓口が2種類あること。ページの窓口は人間のブラウザ向けで、返事はHTML(画面の設計図)。APIの窓口は機械向けで、返事はJSON(データだけ。飾りなし)。APIとは「プログラム同士がやり取りするための窓口」のことで、部屋番号を /api/ で始めるのが世界共通の慣習だ。スマホアプリも充電器も、画面は要らずデータだけ欲しいので、みんなAPIの窓口に並ぶ。
送ったお願い(リクエスト)
ボタンを押す
返ってきた返事(レスポンス)
—
Q. スマホアプリは、ページの窓口とAPIの窓口のどちらを使う?
API。アプリは画面(見た目)を自分の中に持っていて、サーバに欲しいのは中身のデータだけだから。同じ理由で充電器も他社システムもAPIに並ぶ。
STEP 4
インターネットはバケツリレーなので、途中に必ず「中継者」がいる。ハガキで送るか、封筒で送るか。
リクエストは何台もの中継機器を経由して届く。http(sなし)はハガキ——途中の誰からも中身が丸見えだ。httpsは暗号化という封をした封筒——中継者には意味不明な文字列にしか見えず、宛先のサーバだけが封を開けて読める。今どきsなしのサイトにパスワードを入れてはいけない理由を、下で目撃してほしい。
途中の中継者から見えるもの
—
宛先のサーバが読めるもの
—
Q. httpsなら、送った内容は誰にも読まれない。○か×か?
×。途中の中継者には読めないが、宛先のサーバは封を開けて読める。だから「どこに送るか」の判断は暗号化とは別に必要。
STEP 5
現代の画面づくりの根本思想を1つだけ学ぶ。「画面を直接いじらない。データを変えると、画面が勝手に付いてくる」。
Reactは画面を「部品(コンポーネント)」の組み合わせで作る道具だ。そして最大の発明は、画面をデータの鏡にしたこと。下の実験では、左の「データ」だけを操作する。右の「画面」を書き換えるコードはどこにも存在しないのに、画面は必ずデータに追従する。
特に「単価を変更」に注目。データを1箇所変えただけで、画面の全行の料金が一斉に描き直される。もし画面を手でいじる方式なら、行の数だけ書き換え漏れのリスクがある。鏡方式なら漏れは原理的に起きない。
データ(状態)— 触るのはこっちだけ
画面 — Reactが自動で描き直す
Q. 「単価変更」ボタンは画面の各行を書き換えるコードを持っている。○か×か?
×。単価というデータを1つ書き換えただけ。各行の再描画はReactが「鏡」として自動でやっている。
STEP 6
Webの画面は3つの言語の分業でできている。骨組みがHTML、見た目がCSS、動きがJavaScript。デザインを作る=主にCSSを書くこと。
ではプロはCSSをどう書くのか。部品ひとつひとつに色を塗るのではなく、まずデザイントークンという「ルール表」を作る。テーマ色は紫、角丸は16px、余白は18px——という変数の一覧表だ。ページ内の全部品はこの表を参照して描かれるので、表を1箇所書き換えれば、ボタンもカードもタグも一斉に変わる。STEP 5の「画面はデータの鏡」とまったく同じ思想が、デザインにも使われている。
下の実験では、左のルール表だけを操作する。右のUI部品を個別に塗り直すコードはどこにもないのに、全部品が追従することを確かめてほしい。
デザイントークン(ルール表)— 触るのはこっちだけ
画面 — 全部品がルール表を参照している
渋谷パーキング 2F
空き 3口 / 50kW
Q. サービス全体のボタン色を紫から緑に変えたい。CSSを何箇所直す?
トークン方式なら1箇所(ルール表の色変数だけ)。部品ごとに色を直接塗っていたら、ボタンの数だけ直して回ることになり、必ず塗り漏れが出る。
STEP 7
データベースの正体はExcelの表とほぼ同じ。違いは「命令文(SQL)で操作する」ことだけ。
データベースはテーブル(=シート)の集まりで、行=データ1件、列=項目。Excelと違うのは、何百万行でも速く、複数人が同時に触っても壊れず、プログラムから命令文で操作する点だ。その命令文の言語がSQLで、実務の9割はたった4種類:探して(SELECT)/書き足して(INSERT)/直して(UPDATE)/列を増やして(ALTER)。
下のボタンは日本語の指示。押すと、それがSQLに翻訳されて表が変わる。この「翻訳」を裏で自動でやってくれる道具がPrisma(通訳)だ。
日本語 → SQLへの翻訳(Prismaの仕事)
member テーブル
Q. 4つの命令のうち、「表の形そのもの」を変えるのはどれ?
ALTER。列が増減する=ヘッダー行が変わる。残り3つは中身(行)の操作。この違いがSTEP 16の伏線になる。
STEP 8
PythonもJavaもJavaScriptも、正体は同じ。「人間語と機械語(0と1)の間の通訳」であり、翻訳のされ方と得意分野が違うだけ。
コンピュータが直接理解できるのは機械語(0と1の列)だけ。人間には書けないので、人間が読み書きできる中間の言葉=プログラミング言語を書き、それを機械語へ翻訳してから実行する。翻訳には2流派ある:コンパイル=事前に全文翻訳しておく(Java・C。速いが手間)、インタプリタ=その場で逐次通訳する(Python・JavaScript。手軽)。下の実験で、同じ1つの命令が言語ごとにどんな姿になるかを見比べてほしい。
命令:「充電量12.5kWhに単価36円を掛けて、料金を表示して」
言語のボタンを押す
Q. コンピュータが翻訳なしで直接理解できるのはどれ?
機械語だけ。Python・Java・JavaScriptはすべて、実行前か実行中に機械語へ翻訳されている。だから「どの言語で書いても最後は同じ0と1」——STEP 27の積み木の話につながる。
STEP 9
JS・TS・Node・npm・React・Next.js——似た名前の道具たちの関係は、家系図を1枚見れば二度と混乱しない。
昔、JavaScriptという運転手はブラウザという車しか運転できなかった。2009年にNode.js——ブラウザの外(サーバや手元のPC)でJSを動かすエンジン(実行環境)——が生まれ、同じ運転手がサーバという2台目の車を運転できるようになった。これが「フロントもバックも同じ言語」の起点だ。Nodeとセットのnpmは世界最大の部品市場で、Prismaもここで配られている。そしてライブラリ=道具箱(自分が主役で、必要なとき道具を呼ぶ)、フレームワーク=骨組み(向こうが主役で、決められた枠に自分のコードをはめる)。家系図の各行をクリックして確かめてほしい。
解説
Q. Node.jsは新しいプログラミング言語である。○か×か?
×。言語はあくまでJavaScriptで、Nodeはそれをブラウザの外で動かすための実行環境(エンジン)。言語と実行環境の区別が付けば、この家系は迷わない。
STEP 10
どの言語にも「定番の骨組み」が1〜2個ある。名前と性格を知れば、案件票のFW欄からそのシステムの出自・年代・現場の空気まで読めるようになる。
復習:フレームワーク=骨組み(向こうが主役で、決められた枠に自分のコードをはめる)。そして骨組みの名前はシステムの身分証だ。Spring Bootとあれば大企業の基幹、Laravelなら中小Webの受託、Strutsなら20年選手のレガシー——名前1つで現場が透ける。まず図鑑で12人の登場人物を知り、次のクイズで案件票を読んでみよう。よくある誤解を1つ先に:AngularはJavaではない。JavaとJavaScriptは「インドとインドネシア」くらい別物で、AngularはJavaScript側の家系だ(Java文化の会社がフロントにAngularを選びがちなので同居はしている)。
フレームワーク図鑑(クリックで解説)
解説
案件票読解クイズ:FW欄からどんな現場か当てる(1/4問目)
Q. 案件票に「Struts」とあったら、何を読み取る?
2000年代生まれの骨組み=20年選手のレガシーシステム。つまり中身は「保守」か「モダンへのリプレイス」案件。新規開発でStrutsを選ぶ現場は今は存在しない。
STEP 11
STEP 0の地図が実際に動く。光る場所を目で追うこと。「どこで動いているか」が見える人と見えない人で、開発の会話力が段違いになる。
実験は3本。①ページを開く:ブラウザ→サーバ→DB→サーバ→ブラウザと一周する。サーバ上でページの部品(サーバコンポーネント)が実行され、完成したHTMLだけが客席に届くのがNext.js(App Router)の標準スタイルだ。②充電器がAPIで報告:今度はブラウザが一切関与しない。機械(充電器)がJSONというデータ形式で窓口(API)に報告し、DBに1行増える。③壊れたデータ:数値のはずの欄に文字が入ったデータは、DBに届く前に「型チェック」の検問で弾かれる。
ブラウザ(客席)
Next.jsサーバ(厨房)
ページの道
APIの道
PostgreSQL(冷蔵庫)
| date | kwh | price |
|---|
通信ログ
Q. ②を実行した直後、会員のスマホ画面に新しい履歴は見えている?
見えていない。DBに書かれただけで、画面は次にページを開き直したときに最新化される。この「ズレ」を理解しているかが初心者と実務者の分かれ目。
STEP 12
案件票に頻出する「Next.js(App Router)」の正体。約束は3つだけ——フォルダがURLになる・部品は厨房が標準・フォームには近道がある。
Next.jsにはページの作り方の旧方式(Pages Router)と、2023年頃からの現行標準App Routerがある。案件票がわざわざApp Routerと書くのは「新方式で書ける人か」を確認したいからだ(旧方式しか知らない経験者が大勢いる)。
約束1:フォルダの形が、そのままURLの形になる。appフォルダの中にhistoryフォルダを掘ってpage.tsxを置けば、/history というページが生える。フォルダ名を [id] のように角括弧にすると「可変の部分」になり、/history/123 でも /history/456 でも同じファイルが応答して、123という値を受け取れる。下の実験で、URLを押すとどのファイルが応答するかを確かめてほしい。
appフォルダの中身(プロジェクトの実物)
何が起きるか
約束2:部品は「厨房(サーバ)で動く」のが標準。App Routerでは、何も指定しなければ部品はサーバ側でだけ実行され、完成したHTMLだけが届く(サーバコンポーネント)。押した瞬間の反応や入力中のチェックなど、お客さんの手元で動く必要がある部品だけ、ファイル先頭に "use client" と名札を付けて客席に出す。どちらにすべきかの仕分けが、App Router設計の日常だ——下のクイズで感覚を掴んでほしい。
仕分けクイズ:この部品はサーバ? use client?(スコア 0 / 5)
約束3:フォームには近道がある。「プラン変更を保存」のようなフォーム処理は、昔は専用のAPIを別に作る必要があったが、App RouterではServer Actionsという仕組みで、フォームからサーバの関数を直接呼べる。ただしスマホアプリや充電器など「画面以外の相手」との窓口は、これまで通りREST API(route.ts)を立てる。使い分けはこうだ:自分の画面のフォーム=Server Actions、外部の相手=API。
Q. 何も指定せずに作った部品は、サーバとブラウザのどちらで動く?
サーバ。これがApp Router最大の変更点で、旧方式とは標準が逆。ブラウザで動かしたい部品にだけ "use client" の名札を付ける。
STEP 13
画面が変わることと、保存されることは、完全に別の仕事。ここを混同しないことが、この教材で一番大事な理解かもしれない。
いいねボタンを押すと数字が増える。だがその数字がブラウザのメモリの中だけにあるなら、再読み込みした瞬間に消える。本当に残すにはDBへの保存(API経由)が必要だ。そして本物のサービスは1クリックで「画面を即+1」と「裏でDBに保存」の2つを同時にやっている。
先に画面を変えてしまう方式を楽観的更新と呼ぶ(保存はたぶん成功すると楽観する)。Xのいいねがこれで、押した瞬間ハートが赤くなるが保存完了は待っていない。失敗したらそっと巻き戻す。逆に保存を待ってから画面を変える「慎重版」もある。使い分けの基準は失敗したときの実害:いいね程度なら楽観的に気持ちよく、課金や充電開始のような取り消せない操作は慎重に。
ブラウザ(画面のメモリ)
DB(like_count テーブル・本当の記録)
再読み込み後の画面はこの値から始まる
ログ
Q. 楽観的更新で通信が失敗すると何が起きる?(実験で確認してから答え合わせ)
一度増えた画面の数字が巻き戻る。ユーザーには「増えたのに戻った」と見えるので、いいね程度でしか許されない体験。だから決済では使わない。
STEP 14
なぜ一度ログインすると、次のページでも「佐藤さん」と覚えてくれているのか。サーバは実は誰のことも覚えていない。
リクエストは1回ごとに独立していて、サーバから見れば毎回「初対面」だ。そこでログイン成功時にサーバはCookie(ブラウザが自動で持ち歩く小さな会員証)を発行する。以降ブラウザは、同じ建物へのお願いに毎回自動で会員証を添付し、サーバは会員証を見て「佐藤さんですね」と分かる。ログアウト=会員証を破棄すること。
ブラウザのCookie入れ(会員証ケース)
(空っぽ)
ログ
Q. ログアウトすると何が起きる?
ブラウザの会員証(Cookie)が破棄される。サーバが何かを忘れるのではなく、次のお願いに会員証が付かなくなるので「どなたですか」に戻る。
STEP 15
運営会社でも、あなたのパスワードを見ることはできない。見ないのではなく、原理的に見えない仕組みで保存している。
パスワードをそのままDBに保存すると、流出した瞬間に全滅する。そこでハッシュ化——入力を、二度と元に戻せない別の文字列に変換する一方向の処理——をしてから保存する。ログイン時は、入力されたパスワードを同じ方法でハッシュ化し、ハッシュ同士を比較する。元に戻せなくても、一致するかどうかは判定できる。これが「照合はできるのに、誰も中身を見られない」からくりだ。
変換の記録(1文字違うと別物になるのを見る)
DBのmemberテーブル(password列の実物)
佐藤 | a1f8...c2(ハッシュのみ) 鈴木 | 9d3e...71(ハッシュのみ)
Q. 元に戻せないのに、どうやってログインの照合をしている?
入力された値を同じ方法でハッシュ化して、保存済みハッシュと比較する。元に戻す必要はなく、「同じ入力なら同じハッシュになる」性質だけで照合できる。
STEP 16
STEP 7のALTER(列を増やす)を、チーム開発で事故らせないための仕組み。正体は「変更通達文書の綴り」。
なぜ通達が要るのか。同じ表が複数の場所に存在するからだ——各メンバーの開発PC、テスト環境、本番。運用が始まってから「プラン列を足したい」となったとき、4箇所を手作業でバラバラに直せば必ずどこかでズレて事故る。そこで「◯月◯日付:member表にplan列を追加せよ」という通達ファイル(中身はALTER文)を作り、日付順に綴じる。どの環境でも、綴りを上から順に全部適用すれば必ず同じ形になる。
Prismaでは、設計図(schema.prisma)を書き換えてコマンドを打つと、この通達が自動生成される。①→②の順で押して、「設計図を変える」と「DBが変わる」が別の瞬間であることを確認してほしい。
schema.prisma(設計図・唯一の正)
migrationsフォルダ(通達の綴り)
DB(member テーブル)
ログ
Q. ①を押した時点(②の前)で、DBは変わっている?
変わっていない。設計図を書き換えただけ。migrateを実行して通達が発行・適用されて初めてDBの形が変わる。この2段階が「安全」の正体。
STEP 17
現場に入った初日から使う道具。正体は「コードのセーブポイント管理」と「平行世界での安全な実験」。
Gitは変更履歴の管理道具だ。コミット=セーブポイントを打つこと。いつでも過去のセーブに戻れるので、壊すことを恐れず変更できる。ブランチ=平行世界を作ること。本流(main)に触らず実験し、うまくいったらプルリクエスト(PR)——「この変更を本流に合流させてください」という申請書——を出す。申請はレビュー(人間やAIの検査)を通ってから合流する。この教材で何度も出てきた「PR」「月200件」「AIレビュー」の舞台がここだ。
履歴(セーブポイントの列。●が現在地)
ファイルの中身(料金表.ts)
Q. ブランチで実験する利点は?
本流(main)を一切汚さずに試せること。失敗したらブランチごと捨てればよく、成功したらPRのレビューを通して安全に合流できる。
STEP 18
時間のかかる処理をどう扱うか。待ち方の設計はUXの設計そのもの。
同期=レジの前で処理が終わるまで立って待つ。単純だが、待っている間は何もできない——画面が固まる。非同期=番号札をもらって席で待つ。受付だけ済ませて手元は自由、完了したら呼ばれる。AI処理やファイル変換のような数秒〜数分かかる仕事は非同期が定石だ。下の実験では、処理中に「反応チェック」ボタンを連打して、画面が生きているかを確かめてほしい。
ログ
Q. 同期実行中に反応チェックを押すとどうなった?なぜ?
押せない(反応しない)。処理が終わるまでその場を離れられないのが同期。ユーザーには「固まった」に見えるので、長い処理を同期でやってはいけない。
STEP 19
エラーは怖い呪文ではなく、犯人の残した指紋。読み方さえ知れば、原因の大半はログが教えてくれる。
障害対応の第一歩は「エラーメッセージを読むこと」。意外なほど多くの人が読まずに慌てる。メッセージには何が・どこで起きたかが書いてあり、パターンは有限だ。下の事件簿で、ログを読んで4人の容疑者から犯人を当ててほしい。
エラーログ(事件現場)
Q. ECONNREFUSED 127.0.0.1:5432 —— 5432という番号から何が分かる?
5432はPostgreSQLの標準の接続口番号。つまり「DBへの接続が拒否された」=DBが落ちているか、接続先の設定ミス。番号が犯人の指紋になる例。
STEP 20
「検索が遅い」の原因第1位。10万件から1人を探すのに、1ページ目からめくるか、五十音の索引で飛ぶか。
DBは何も工夫しないと、条件に合う行を探すために全行を上から順に確認する(フルスキャン)。10万件なら10万回。そこでインデックス(索引)——特定の列の値で引ける五十音順の目次——をあらかじめ作っておくと、目的の行へほぼ直行できる。ただし索引はタダではない:書き込みのたびに索引の維持コストがかかるので、「よく検索する列にだけ張る」のが設計だ。
Q. 全部の列にインデックスを張れば最速になる。○か×か?
×。索引は書き込みのたびに維持コストがかかるため、増やすほど書き込みが遅くなる。「よく検索する列にだけ」が正解。
STEP 21
同じ画面を作るのに、DBへの「聞き方」だけで所要時間が100倍変わる。ORM(通訳)任せで起きる最有名バグ。
会員100人の一覧に、それぞれの充電履歴を添えて表示したい。素朴に書くと「まず100人のリストをもらう(1回)→1人ずつ履歴を聞きに行く(100回)」で合計101回、冷蔵庫を開けることになる。これがN+1問題(Nは人数)。正解は「会員と履歴をまとめて1回でください」と聞くこと(SQLのJOIN、Prismaならincludeという書き方)。
DBに届いた質問(SQL)
Q. 会員が1万人になったとき、素朴な書き方のクエリ回数は?
10,001回。まとめて聞く書き方なら変わらず1回。人数に比例して遅くなるか、一定のままか、が本質的な違い。
STEP 22
よく聞かれる質問の答えを、毎回冷蔵庫まで取りに行かず手元のメモ帳に書いておく。ただし本当の難しさは「メモの消し時」。
「人気の充電スポット一覧」のような、みんなが見るのに滅多に変わらないデータは、毎回DBで重い集計をするのが無駄だ。そこで一度計算した答えをRedis(メモ帳役の高速な保管庫)に書き留め、次からはそこから返す。1回目(MISS=メモにない)は遅く、2回目以降(HIT)は一瞬——を体験してほしい。
そして「スポット情報が更新された」を押すとメモを破棄する。これを無効化と言い、キャッシュ設計の本丸はここ。無効化を忘れると「古い情報を返し続ける」事故になる。ちなみにAIのプロンプトキャッシュ(同じ前提文を割引価格で使い回す仕組み)も原理はこのメモ帳と同じだ。
ログ
Q. キャッシュがあるのに古い情報が表示され続けるバグ。原因はどこにある可能性が高い?
無効化の漏れ。データを更新する処理のどこかで「メモ帳を破棄する」一手が抜けている。
STEP 23
相手のAPIには「1秒に3件まで」のような利用上限がある。ぶつかると429エラー。人気店に10人で押しかけるか、並んで入るか。
まずA(制御なし)を押す。10件同時に送ると3件だけ成功し、7件が429(上限超過)で失われる。次にB。全件を行列(キュー)に積んで毎秒3件ずつ流し、途中で429を食らったら少し待って再送する——待ち時間を1秒、2秒、4秒と倍にしていく再送の定石を指数バックオフと呼ぶ。遅くはなるが1件も失わない。
この構造はAIのAPI(Claude・OpenAI)でも決済APIでも全く同じ。大量のファイルをAIに処理させるサービスが「安定稼働が難しい」と言われる理由の大半は、この流量制御の設計にある。
ログ
Q. 429エラーは「障害」か?
障害ではなく仕様。相手が「ペースを落として」と言っているだけなので、正しい対応は再送設計であって、エラー通知で人を起こすことではない。
STEP 24
事故は「起きたら」ではなく「起きたとき」。守りの最後の砦は、戻れる場所があるかどうか。
バックアップ=ある時点のDBの完全な写しを、別の場所に取っておくこと。定期的(毎晩など)に自動で取るのが基本だ。そして重要な格言がある——「バックアップは、復元のリハーサルをして初めてバックアップと呼べる」。取ってあるつもりが壊れていて戻せない、が実際の事故で一番多い。下では、バックアップを取ってから事故を起こす順と、取らずに事故を起こす順の両方を試せる。
DB(member テーブル)
| id | name |
|---|
ログ
Q. バックアップを「取っている」だけでは不十分と言われるのはなぜ?
復元できて初めて意味があるから。復元手順のリハーサルをしていない現場は、事故当日に「戻し方が分からない・実は壊れていた」に直面する。
STEP 25
ネットワークは必ず失敗し、失敗すると再送が起きる。そのとき課金が2回実行されたら大事故。全ステップの知識が合流する最終試験。
充電開始と同時に300円を課金する。ところが応答が届かず、アプリが同じ注文を自動再送した——さて課金は何回実行されるべきか? もちろん1回。これを保証する性質を冪等性(べきとうせい)と呼ぶ:同じ操作が2回届いても、結果は1回と同じ。
実現方法は拍子抜けするほど単純で、注文に一意の番号(冪等キー)を付け、サーバは「同じ番号の注文は2回実行せず、前回の結果だけ返す」。まずキーなしで二重課金の事故を起こし、次にキー付きで防がれるのを見てほしい。決済会社のAPIには必ずこの仕組みが備わっている。
ログ
DB(charge_payment テーブル)
| id | 金額 | 冪等キー |
|---|
Q. STEP 23のリトライ(再送)とSTEP 25の冪等性は、なぜセットで必要?
リトライは「失敗したらもう一度送る」仕組みなので、同じ注文が複数回届く状況を自ら作り出す。だから再送を設計するなら、受け手側の冪等性が同時に必須になる。攻め(リトライ)と守り(冪等性)は常に一対。
STEP 26
最後は、この教材全体の裏テーマ。AIの出力の質は、AIの賢さではなく、指示の言語化の質で決まる。
AIに「いい感じにやって」と頼むと、毎回違う「いい感じ」が返ってくる。AIが悪いのではなく、「いい感じ」の定義を渡していないからだ。プロの指示書は4点を必ず埋める:入力(何を渡すか)・出力(どんな形で返すか)・判断基準(何を良しとするか)・禁止事項(やってはいけないこと)。この4点があると、出力は安定し、直したいときは指示書を直せば再発しない。実は「要件定義」も「タスク分解」も、やっていることはこれと同じ——曖昧なものを、実行可能な言葉に変換する仕事だ。
AIからの返答
—
指示書(プロの頼み方)
入力:7月の充電履歴データ 出力:日本語3行以内 判断基準:合計金額と前月比を必ず含む 禁止:データにない数値の推測
Q. AIの出力が毎回ブレるとき、最初に直すべきはAIの設定か、指示書か?
指示書。判断基準と出力形式が言語化されていないことがブレの主因。指示書を直せば、同じ修正がチーム全員のAI利用に効く。
STEP 27
この教材で学んだ全部は、実は1枚の積み木に収まる。一番下は電圧、一番上はあなたの気持ち。1回のタップの旅を見届けて修了。
ITの世界は層(レイヤー)の積み木でできている。各層は「すぐ下の層の使い方」だけを知っていて、中身は知らなくていい——アプリを書く人は電圧を知らないし、あなたがタップするときJSONを知らない。この「中身を隠して使い方だけ見せる」仕組みを抽象化と呼び、だからこそ人類は電子の物理から巨大なサービスまでを積み上げられた。エンジニアの職種(インフラ・バックエンド・フロントエンド・デザイナー・PM)も、実はどの層を担当するかの分業だ。
そして注目してほしいのが両端だ。一番上(人間の意思)と一番下(電圧)だけがアナログ——連続的で、曖昧で、無段階。真ん中だけがデジタルだ。デジタルとは、アナログな気持ちをアナログな物理現象で確実に運ぶための「中間の包装」だと言える。
第6層 人間の意思 アナログ
第5層 言葉とUI(画面・ボタン)
第4層 アプリ(コード・API・DB)
第3層 通信(DNS・パケット・HTTPS)
第2層 ビット(0と1)
第1層 物理(電圧・光・磁気) アナログ
Q. この積み木で「アナログ」なのはどの層?
両端。第6層(人間の意思=曖昧で連続的)と第1層(電圧・光=連続的な物理現象)。真ん中のデジタルは、この2つのアナログの間を確実に運ぶための包装。
ここまでの例えは入門のための地図であって、実物とは縮尺が違う。実務レベルに進む人のために、盛った箇所を正直に開示する。
STEP 7で「日本語の指示がSQLに翻訳される」と見せたが、Prismaの本当の翻訳元は日本語ではなくTypeScriptのコードだ。実際はこの2段翻訳になっている:
日本語の要望「プレミアム会員を探して」
↓ 人間かAIがコードに書く
await prisma.member.findMany({ where: { plan: "premium" } })
↓ PrismaがSQLに変換する
SELECT * FROM member WHERE plan = 'premium';ただし前半の「日本語→コード」をAIが担うようになったのがAI駆動開発なので、「日本語からSQLへ」は例えというより、半分現実になりつつある。
| 教材の例え | 本当のところ |
|---|---|
| DBは「Excelの表」 | 構造は同じだが本質差が3つ。インデックス(速く探す索引)、トランザクション(複数の変更を「全部成功か全部なかったことか」にする。課金で必須)、同時実行制御(大勢が同時に書いても壊れない)。Excelにはどれもない |
| 「完成したHTMLだけが届く。JSはほぼ不要」 | 最小限のJavaScriptも一緒に届き、HTMLに後から動きを接続する(ハイドレーション)。「ほぼ」に嘘はないがゼロではない |
| 「画面はデータの鏡。全行が描き直される」 | Reactは実際には全部描き直さず、変わった部分だけ差分更新する(仮想DOM)。思想は鏡、実装は賢い手抜き |
| Redisは「手元のメモ帳」 | 実際はサーバの中ではなく、独立したもう1台の高速保管サーバ。「厨房の隣の小さい冷蔵庫」が正確 |
| マイグレーション=「通達を上から順に適用」 | DB自身が「どの通達まで適用済みか」を記録する専用の表を持ち、二重適用を防いでいる。つまりここにも冪等性がいる |
| 冪等キー「同じ番号は2回実行しない」 | 番号を「覚えておく」には、その番号自体をDBに保存する必要がある。覚え場所の設計まで含めて冪等性の実装 |
| サーバ=「厨房1つ」 | 本番は厨房が複数台あり、負荷で増減する(オートスケール)。だからメモリ上のデータは他の厨房から見えず、共有したい状態はRedisやDBに置く——STEP 13の話は複数台になると更に重要になる |
例えで速く入門し、種明かしで実物に接続する。両方を知っていれば、現場の会話で例えのまま話して恥をかくことはない。
コンポーネント/状態/SQL/スキーマ/マイグレーション/サーバコンポーネント/API/JSON/型チェック/楽観的更新/N+1/キャッシュと無効化/レートリミット/指数バックオフ/キュー/冪等性/HTML・CSS・デザイントークン/ハイドレーション/App Router・use client/URL・パス/リクエストとレスポンス/JSON・API/DNS/HTTPS/Cookie・認証と認可/ハッシュ化/コミット・ブランチ・PR/同期と非同期/インデックス/バックアップと復元/指示書の4点セット/層(レイヤー)と抽象化/機械語・コンパイル/実行環境(Node)・npm/ライブラリとフレームワーク/各言語の定番FW(Spring・Laravel・Rails・FastAPI)。これらは全部、現場の設計会議で今日も使われている言葉だ。次に仕様書やチケットでこれらの単語に会ったとき、頭の中でこのページのどこかが光れば、この教材の目的は達成されている。