← ミライズ労務コンサルティング開発知識シリーズ 目次(全6部)
第 2 部
hokama@mirise ~/project $ npm run dev

開発スタック入門

OS、JavaScript、Node.js、npm、Next.js。
それぞれ別の話に見えて、実は一本の積み木として重なっています。
設計する側が、その積み木の並びを知っておくための資料です。

$ whoami

なぜ設計する人が土台を知るべきか

AI が得意な領域と、人間にしか残らない領域は、はっきり分かれています。

AI が強いのは真ん中です。実装、記法、定型的な処理。ここは速く、質も高い。

弱いのは両端です。

入口 ─ 何を作るべきかの指定

要件、制約、優先順位、許容できるリスク。これは外から与えるしかありません。AI は事務所の業務も、顧問先の事情も、来年の制度改正の見込みも知りません。何を作るべきか、そして何を作るべきでないかは、外部から入力される情報でしかない。

出口 ─ 出てきたものが正しいかの検証

AI は自信を持って間違えます。しかも、間違え方が自然です。検算できない人は、間違いをそのまま本番に入れます。

両端の質を決めるのは語彙

「なんか動きません」としか言えない状態と、「Node のプロセスが 3000 番ポートを掴んだまま終了していない」と言える状態では、返ってくるものがまるで違います。前者に対して AI は推測するしかない。後者なら一手で解決します。

言葉を持っているかどうかが、そのまま解像度になります。土台を知るというのは、知識を蓄えることではなく使える語彙を増やすことだと考えるほうが実態に近いと思います。

ただし、すべてを知る必要はない

ここは正直に書いておきます。抽象化の階層が上がるほど、下の層を知らずに作れる範囲は確実に広がっています。アセンブリを知らなくても優れた Web アプリは作れますし、CPU の命令セットを知らないことが欠陥になる場面はほとんどありません。

問題は知識の量ではなく、どこまで降りられるかです。普段は一番上の層で作業していい。ただし詰まったとき、一段ずつ下へ降りて「ここは正常、ここも正常、ここが怪しい」と切り分けられること。この能力が差になります。

設計とは何か

設計とは、無数にある選択肢のうち、どれを採用しどれを捨てるかを決めることです。

捨てる判断には、捨てたときに何が起きるかの理解が要ります。AI は選択肢を並べることはできますが、責任を負う人間の代わりに捨てる判断はできません。並べるのは AI、決めるのは人間という分担は、当面変わらないと思います。

$ uname -a

OS とは何か

Operating System、日本語では基本ソフト。すべての土台です。

OS が無かった時代、プログラムは機械そのものを直接操作していました。プリンタの型番が変われば、すべてのプログラムを書き直す必要がありました。

OS の役割は二つに集約されます。仲介抽象化です。プログラムとハードウェアの間に立ち、複数のプログラムが同じ機械を奪い合わないよう調停し、面倒な違いを覆い隠して統一的な形で見せる。

ブラウザ エディタ Node.js OS(カーネル) プロセス管理 メモリ管理 ファイル管理 装置の管理 CPU メモリ ディスク・装置
すべてのプログラムは、必ず OS を経由してハードウェアに触れます。直接触ることは許されていません。

OS がしている最大の仕事は「嘘をつく」こと

ここが本質だと思います。OS はそれぞれのプログラムに対して、「この機械はお前専用だ」と思い込ませています。実際には数百のプロセスが同じ CPU とメモリを奪い合っているのに、各プログラムは自分だけが動いていると信じたまま動いています。

CPU については時分割という手法を使います。1つの CPU が数ミリ秒ごとに担当を切り替える。切り替えが速すぎるので、人間には同時に動いているように見えます。

メモリについては仮想メモリを使います。各プログラムに「0番地から始まる自分専用の広大な空間」があるように見せかけ、実際の物理メモリ上のどこに置くかは OS が裏で管理します。

この二つの嘘があるから、私たちはブラウザとエディタとターミナルを同時に開けます。

壁がある理由

OS の内部はカーネル空間ユーザー空間に分かれています。アプリはユーザー空間で動き、ハードウェアには直接触れません。触りたければシステムコールという窓口を通す必要があります。

面倒に見えますが、これは安全装置です。一つのアプリのバグでシステム全体が巻き添えになるのを防いでいます。アプリが落ちても OS は生きている、という当たり前の状態は、この壁が作っています。

血縁関係

OS系譜主な用途
Unix(1969)すべての源流研究機関・大型機
Linux(1991)Unix の思想を独自に再実装サーバーの大半・Android・Vercel の実行基盤
macOSBSD 経由で Unix の直系個人・開発
WindowsMS-DOS 由来の別系統企業の事務端末

macOS が Unix の直系であることが、実務上そのまま効いてきます。Mac のターミナルで Linux 向けの手順がほぼそのまま動くのは、血縁があるからです。Windows で同じ手順が動かないのは、家系が違うからです。

$ whatis javascript

JavaScript とは何か

1995年、ブラウザの中でちょっとした動きをつけるために、約10日で作られた言語です。

Netscape という会社の Brendan Eich が設計しました。当時の目的は控えめなもので、「ボタンを押すと色が変わる」「入力欄が空なら警告を出す」といった程度の仕掛けを想定していました。

よくある誤解

JavaScript と Java はまったく別の言語です。血縁も互換性もありません。当時人気だった Java にあやかった、商標上の判断による命名です。「インドとインドネシアくらい違う」という言い方がされます。

なぜこれほど広まったのか

理由は一つです。世界中のあらゆるブラウザに、最初から入っている唯一の言語だからです。

他の言語でブラウザを動かそうとすれば、利用者にインストールを求める必要があります。JavaScript にはその手間がありません。この一点だけで、他の選択肢を退けました。技術的な優劣ではなく、置かれた場所が勝敗を決めた例です。

知っておくと混乱しない周辺の言葉

言葉意味
ECMAScriptJavaScript の正式な規格名。ES2015 などのバージョン表記はこれを指す
TypeScriptJavaScript に「型」の指定を足したもの。書いた時点で間違いに気づける。最終的には JavaScript に変換されて動く
.js / .ts / .jsx / .tsx拡張子。x が付くものは、後述の React の記法を含むファイル

TypeScript は、AI と組んで開発する場合とくに効きます。型が書いてあると、AI が生成したコードの誤りをその場で機械が検出できるためです。人間の検算を機械が肩代わりしてくれる範囲が広がります。

$ which node

Node.js とは何か

JavaScript を、ブラウザの外に連れ出したものです。

2009年、Ryan Dahl という技術者がやったことは、一言で言えばこうです。Google Chrome の中で JavaScript を動かしている部品(V8 エンジン)を取り出して、単体で動くようにした。

ブラウザ(Chrome) V8 エンジン 画面の描画・DOM 操作 Node.js V8 エンジン(同じもの) ファイル操作・通信 ブラウザの中でしか動かない 普通のプログラムとして動く
エンジンは同じで、周りに付いている装備が違うだけです。ブラウザは画面を描くための装備、Node.js はファイルと通信のための装備を持っています。

これによって JavaScript が、ブラウザの外 ─ つまり普通のコマンドラインプログラムとして、そしてサーバーとして動くようになりました。画面側と裏側を同じ言語で書ける、という現在の状況はここから始まっています。

用語の整理

Node.js は言語ではありません。JavaScript という言語を動かすための実行環境(ランタイム)です。「Node で書く」という表現は、正確には「JavaScript で書いて Node で動かす」ということです。

第1部とのつながり

ターミナルで node app.js と打つとき、何が起きているか。第1部の第4章がそのまま当てはまります。

bash が PATH から /usr/bin/node を探し、自分の複製を作り、その中身を node のプログラムで上書きする。node が起動するプログラムで、app.js はそこへ渡されるただの引数です。app.js 自体が起動しているわけではありません。

Node のプロセスが残り続ける理由

サーバーとして起動した Node は、終わらないことが仕事です。リクエストが来るのを待ち続けるために、意図的に終了しません。

だから Ctrl+C で止めるか、明示的に kill しない限り生き続け、ポートを掴んだままになります。「なぜか 3000 番が使用中」の正体はこれです。異常ではなく、設計どおりの挙動が残っているだけです。

# Mac / Linux $ lsof -i :3000 $ kill -9 <PID> # PowerShell PS> Get-Process node | Stop-Process -Force
$ npm --help

npm とは何か

Node Package Manager。他人が書いた部品を取り寄せる仕組みです。

日付の整形、パスワードの暗号化、CSV の読み込み、PDF の生成。こうした処理は、世界中で毎日誰かが書き直しています。同じものを何度も作るのは無駄です。

npm は、誰かが作って公開した部品(パッケージ)を、1行で自分のプロジェクトへ持ってこられるようにする仕組みです。

3つのファイルの役割

ファイル役割誰が書くか
package.json部品表。何が必要かを列挙する人間(と npm)
package-lock.json実際に入った正確なバージョンの記録npm が自動生成
node_modules/ダウンロードされた部品の置き場npm が自動生成

package.jsonテキストファイルです。人が読めて、機械も読めて、Git で差分が見え、AI にもそのまま渡せる。第1部の原則4「テキストを共通語にする」が、そのまま実装されています。

// package.json(抜粋) { "name": "my-app", "scripts": { "dev": "next dev", "build": "next build" }, "dependencies": { "next": "15.0.0", "react": "19.0.0" } }

なぜ node_modules は巨大になるのか

部品が、別の部品を必要とするからです。そしてその部品が、また別の部品を必要とする。この連鎖が数段続くと、自分で指定したのは3個でも、実際には数百のパッケージが入ります。

これは無駄ではなく、原則2「一つのことをうまくやる」の帰結です。各部品が小さく作られているからこそ、数が増えます。

主なコマンド

コマンド何が起きるか
npm install部品表を見て、必要なものを全部取り寄せる
npm install パッケージ名新しい部品を1つ追加し、部品表にも書き足す
npm run devpackage.json の scripts に書かれたショートカットを実行する
npm cilock ファイルどおりに厳密に再現する。本番やビルド環境向け

npm run dev は、それ自体が何かをするコマンドではありません。package.json に書いてある別のコマンドを呼び出しているだけです。上の例なら、実際に動くのは next dev です。

設計上の判断が要るところ

npm でパッケージを入れるということは、他人が書いたコードを自分の製品に取り込むということです。依存が増えるほど、内容を確認していないコードの割合が増えます。

「その部品は本当に必要か。自分で20行書けば済むものではないか」。この判断は AI に委ねられません。顧客データを扱うのか、どこまでの停止が許容されるのか、といった文脈を持っているのは人間だけだからです。

$ cat package.json

React と Next.js とは何か

順番に見ていきます。Next.js は React の上に乗っているので、React が先です。

React ─ 画面を部品で作る

Facebook が作った、画面を組み立てるためのライブラリです。発想はシンプルで、画面を部品(コンポーネント)の組み合わせとして作ります。

ボタン、入力欄、表、カード。それぞれを独立した部品として書き、必要な場所に置いて組み立てる。同じボタンを10箇所で使うなら、書くのは1回です。

これは第1部の原則2「一つのことをうまくやる」と、原則3「組み合わせて使う」を、そのまま画面作りに持ち込んだものです。Unix が小さなコマンドを組み合わせたように、React は小さな部品を組み合わせます。

Next.js ─ 実務で使うための土台一式

React だけでは足りないものが、実務ではたくさん出てきます。URL とページの対応づけ、表示速度の最適化、本番用にコードを固める作業。Next.js はそれらをまとめて引き受ける枠組みです。

ライブラリとフレームワークの違い

ライブラリは、自分が呼ぶものです。必要なときに手を伸ばす道具箱。

フレームワークは、自分が呼ばれるものです。決まった場所に決まった名前でファイルを置いておくと、向こうから呼びに来ます。

「こちらから連絡しないでください、こちらからかけます」というオーディションの決まり文句になぞらえて説明されることがあります。主導権がどちらにあるかが逆転している、というのが要点です。

Next.js が肩代わりしていること

機能内容
ルーティングapp/about/page.tsx に置くと /about という URL になる。置き場所がそのまま URL
サーバー側描画画面をサーバーで組み立ててから送る。表示が速く、検索エンジンにも読まれる
ビルド開発用のコードを、本番用に圧縮・最適化して固める
画像の最適化閲覧環境に応じたサイズと形式で自動的に配信する

「ファイルを置くと URL になる」という設計は、第1部の原則1「すべてはファイルである」の直系です。半世紀前の発想が、そのまま現代のフレームワークの中で生きています。

Vercel との関係

Next.js を作っている会社が Vercel です。自社で設計したフレームワークを、自社の実行基盤の上で動かしている。だから git push するだけで公開まで進みます。相性が良いのは当然で、同じ会社が両側を設計しているためです。

裏返せば、Vercel 以外で Next.js を動かす場合には、その連携部分を自前で用意する必要が出てきます。これも設計判断の一つです。

$ tree -L 1

全体の層構造

ここまで出てきたものを、一枚に積み上げます。

自分のアプリ あなたが設計して書く部分 Next.js 画面と URL の土台一式 npm で集めた部品 React ほか、世界中の誰かが書いた部分 Node.js JavaScript を動かす実行環境 シェル bash / zsh / PowerShell OS カーネル 資源の仲介と抽象化 ハードウェア CPU・メモリ・ディスク
金色の一番上だけが、自分で書く領域です。下の6層は、すでに誰かが作ったものの上に乗っています。

各層には共通の性質があります。下の層に依存し、上の層に対しては複雑さを隠すということです。

Next.js を書いている間、CPU の時分割を意識することはありません。それが抽象化の目的です。意識しなくていいから、上の層の仕事に集中できる。

ただし、隠されているだけで、無くなってはいません。普段は見えない下の層が、問題が起きたときにだけ姿を現します。そのとき、そこに何があるかを知っているかどうかで対応が変わります。

見方を変えると

この7層は、そのまま「誰が責任を持つか」の区分でもあります。

ハードウェアからシェルまでは、OS の作り手の責任。Node.js と npm の部品は、その公開者の責任。Next.js は Vercel の責任。そして一番上の層だけが、あなたの責任です。

依存を増やすということは、他人の責任範囲を増やすことでもあります。楽になる代わりに、自分でコントロールできない部分が増える。この取引を意識的に行えるかどうかが、設計の質を分けます。

$ echo $?

層で切り分ける

層構造を知っている実利は、ほぼここに集約されます。

原則は一つです。下から上へ確認する。上の層で悩む前に、下の層が正常であることを確かめる。下が壊れていれば、上で何をしても直りません。

症状疑う層確認方法
コマンドが見つからないシェル / PATHwhich node で場所を確認
ポートが使用中OS / プロセスlsof -i :3000 で犯人を特定
npm install が失敗するnpm / ネットワークエラーの最終行を読む
起動はするが画面が白い自分のコードブラウザの開発者ツールのコンソール
ローカルは動くが Vercel で落ちる環境差Node のバージョン、環境変数、ビルドログ
昨日まで動いていた依存関係lock ファイルの差分を確認

AI に渡すときの形

切り分けができていると、AI に渡す情報の質が変わります。

# 情報量の少ない依頼 デプロイできません。直してください。 # 切り分け済みの依頼 ローカルの npm run dev は正常。 Vercel のビルドログで、環境変数 DATABASE_URL が undefined というエラーで停止している。 ローカルの .env.local には設定済み。

後者に対して AI は、Vercel 側の環境変数設定が抜けているという結論に一手で到達します。前者に対しては、可能性を10個並べることしかできません。

ここで効いているのは技術力ではなく、どの層で止まったかを言語化する能力です。

最後に

この資料の内容を全部覚える必要はありません。層の名前と並び順、そして「困ったら一段下を疑う」という手つきさえ身についていれば十分です。

実装は AI が速い。ならば人間が持つべきは、何を作るかを決める力と、出てきたものを疑う力です。そのどちらも、土台の構造を知っていることを前提にしています。