- ・Nomad Listの初期版がどのような技術構成で作られていたのかが分かる。
- ・PHP・jQuery・JSONファイルという地味な構成を選んだ理由が分かる。
- ・1人開発で「開発速度」を最大化するための設計思想が分かる。
初期Nomad Listの技術スタック
Levelsが2014年に公開したMVP開発環境は、おおむね次のような構成だった。
Client
├── HTML
├── CSS / SCSS
├── JavaScript
└── jQuery
Server
├── Nginx
├── PHP-FPM
├── PHP
└── 一部 Node.js
Data
└── JSON files
Infrastructure
├── Linode VPS
└── Ubuntu
Levelsは当時、自分の複数のサイトを月40ドル程度のLinode VPS 1台で動かしていた。
重要なのは、それぞれの技術が特別だったことではない。
むしろ逆だ。
Levelsがすでに使える技術だけで構成されていた。
フレームワークをほとんど使わない
フロントエンドにはHTML、CSS、JavaScriptを直接利用し、JavaScriptではjQueryを使用していた。
バックエンドの中心はPHP。
WebサーバーにはNginxを置き、PHP-FPM経由でPHPを実行する。
Browser
↓
Nginx
↓
PHP-FPM
↓
PHP Application
↓
JSON Data
現在ならLaravel、Next.js、Rails、Djangoなどのフレームワークを選択するケースも多い。
しかしLevelsは、フレームワークを増やすことで生まれる学習コストや複雑性を避けた。
彼が最適化していたのは、アーキテクチャの美しさではない。
Idea
↓
Build
↓
Deploy
↓
User Feedback
↓
Improve
このループをできるだけ短くすることだった。
データベースの代わりにJSONファイル
初期の技術構成で特に特徴的なのが、データ保存だ。
LevelsはMVP段階では、本格的なデータベースを使わずJSON形式のファイルへ保存する方法を使っていた。
概念的には、都市データは次のようになる。
{
"city": "Chiang Mai",
"country": "Thailand",
"cost": 700,
"internet": 25,
"temperature": 28
}
一般的なWebサービスなら、PostgreSQLやMySQLなどを使い、次のようなテーブルを作る。
CREATE TABLE cities (
id INTEGER PRIMARY KEY,
name VARCHAR(255),
country VARCHAR(255),
cost INTEGER,
internet_speed FLOAT,
temperature FLOAT
);
しかし、初期段階ではサービス自体の仕様がまだ固まっていない。
明日、新しいフィールドが必要になる可能性もある。
そのたびにマイグレーションを考えるより、JSONへキーを一つ追加した方が速い。
Levelsはその速度を優先した。
JSONを使うメリット
MVP段階では、JSONファイルにはいくつか明確なメリットがある。
- データベースサーバーが不要
- スキーマ設計が不要
- セットアップが簡単
- ファイルを見るだけでデータを確認できる
- フィールド追加が容易
- バックアップも単純
特に1人で短期間に複数サービスを作る状況では、環境構築の時間を削減できる。
一方で、当然デメリットもある。
- 複数ユーザーによる同時書き込みに弱い
- 高度な検索が難しい
- JOINができない
- トランザクション管理がない
- データ量が増えると性能が落ちやすい
つまり、JSONファイルは万能なデータベースではない。
小さいMVPを最速で作るための選択だった。
プロジェクト構成もシンプル
Levelsが公開していた当時のディレクトリ構成は、概念的には次のようなものだった。
/
├── _assets/
├── public/
│ └── assets/
├── app/
├── lib/
├── workers/
├── logs/
└── data/
それぞれの役割はシンプルだ。
public/
ブラウザから直接アクセスするCSS、JavaScript、画像など
app/
PHPやJavaScript、SCSS、設定ファイルなど
lib/
StripeやOAuthなど外部ライブラリ
workers/
バックグラウンド処理
logs/
ログファイル
data/
JSON形式のデータ
複雑なレイヤー構造やマイクロサービスは存在しない。
プロダクトが小さい段階では、コードベース全体を1人で把握できること自体が大きな利点になる。
Nginxをルーターとして使う
現代のWebフレームワークでは、アプリケーション側でルーティングを定義することが多い。
例えばNext.jsなら、
/app
├── page.tsx
├── cities/
│ └── page.tsx
└── users/
└── page.tsx
のようにURLとファイルを対応させられる。
Levelsの初期構成では、Nginx側でURLをPHPファイルへ振り分ける方式を取っていた。
Request
↓
Nginx
↓
PHP file
↓
Response
現代的ではないが、構成要素が少ない。
1人で全部を管理するなら、この「理解しきれる」という性質は大きい。
バックグラウンド処理にはcron
定期処理にも専用のジョブサービスは使わない。
cronからPHPスクリプトを定期実行する。
例えば次のような形だ。
* * * * * php -f /path/to/workers/job.php >> /path/to/logs/job.txt
処理の流れは非常に単純。
cron
↓
PHP Worker
↓
API取得・データ更新など
↓
Log
現代なら、
- AWS SQS
- BullMQ
- Celery
- Cloud Tasks
- Temporal
などを使う選択肢もある。
ただし、それらを導入すると新しい管理対象も増える。
ユーザーが少ない段階では、cronだけで十分なケースも多い。
1台のVPSに複数サービス
インフラも同じ思想で作られていた。
Levelsは1台のLinode VPS上で複数サイトを運用していた。
Internet
↓
Linode VPS
│
├── Nginx
│ ├── Project A
│ ├── Project B
│ └── Nomad List
│
├── PHP-FPM
├── Workers
└── Data
現在なら、
Frontend → Vercel
API → Railway
DB → Supabase
Storage → S3
Queue → Cloud Service
のようにサービスを分割する構成も簡単に作れる。
しかし管理対象は増える。
Levelsの場合、新しいサービスを作るたびに既存環境をコピーし、ドメインや設定を書き換える。
一度自分用の型が完成すれば、短時間で新しいサービスを公開できる。
技術スタックを固定するメリット
Levelsの開発方法で特に重要なのが、毎回技術スタックを変えないことだ。
新しいサービスを作るたびに、
Next.jsかNuxtか
GoかRustか
PostgreSQLかMongoDBか
AWSかCloudflareか
と考えていると、それだけで時間を消費する。
技術選定は楽しい。
そしてプロダクトは完成しない。
Levelsは長年、自分が知っている技術を繰り返し使っている。
その結果、コードを書く速度だけでなく、
- デプロイ方法
- バグの原因
- サーバー設定
- ライブラリ
- 開発環境
まで理解した状態で開発を始められる。
これは1人開発ではかなり強い。
2024年でもPHP、jQuery、SQLite
さらに興味深いのは、この思想が2014年だけのものではないことだ。
2024年に公開されたLex Fridmanとの対談でも、Levelsは自身の基本的なスタックとしてPHP、jQuery、SQLiteなどを挙げている。
10年前と比較すると、Web開発のトレンドは大きく変わった。
React。
Next.js。
Serverless。
Edge Runtime。
Rust。
Kubernetes。
それでもLevelsは、必要がない限り全面的な技術移行を行っていない。
理由は単純だ。
今の技術でプロダクトを作れているから。
技術的に新しいものと、ビジネスにとって良いものは必ずしも一致しない。
現代にNomad List型サービスを作るなら
Levelsの構成をそのまま真似する必要はない。
2026年なら、もっと簡単な選択肢もある。
例えば、
Next.js
↓
Supabase
↓
Vercel
でも作れる。
バックエンドを明確に分離するなら、
Next.js
↓
Go API
↓
PostgreSQL
でもいい。
Cloudflare中心なら、
Cloudflare Pages
↓
Cloudflare Workers
↓
D1 / R2
のような構成も可能だ。
重要なのは、どれが最もモダンかではない。
自分が最速で使えて、現在の規模を処理できるか。
これが判断基準になる。
スケールする前からスケールの問題を解かない
Webサービスを作るとき、
「100万人来たらどうする?」
という話がよく出る。
しかしユーザーがまだ0人なら、100万人対応は現在の問題ではない。
初期Nomad Listでは、
- JSONファイル
- cron
- PHP
- jQuery
- 1台のVPS
で十分だった。
ユーザーが増え、本当に問題が起きた段階で改善すればいい。
逆に、最初から複雑な分散システムを作れば、
- 開発時間が増える
- バグの場所が増える
- インフラ管理が増える
- 学習コストが増える
というコストを先に支払うことになる。
まだ存在しないユーザーのために。
Nomad Listから学べる技術設計
Nomad Listの初期アーキテクチャから学べるのは、PHPやJSONファイルを使うべきだということではない。
重要なのは、技術選定の判断基準だ。
今必要か?
↓
YES → 実装する
↓
NO → 実装しない
JSONで十分ならJSON。
cronで十分ならcron。
1台のVPSで十分なら1台。
そして、本当に限界が来たときに次へ移る。
1人や少人数でプロダクトを作る場合、エンジニアリングリソースそのものが限られている。
だからこそ、
システムの複雑さを増やさないこと自体が技術戦略になる。
Nomad Listは、その考え方をかなり極端な形で示したプロダクトの一つだ。