はじめに
前回は Step 0 として、「Hello」と時刻を表示するだけのツールを、自宅サーバーで外から使えるようにするまでを紹介しました。ビルド、常駐、中継、認証という、Web で何かを動かすための経路を一本通した回です。
今回から Step 1 に入ります。Step 1 のテーマは画面づくりです。ブラウザの中で入力を受け取り、計算して、結果を表示する小さなツールを作りました。
この回では、プログラムを書き始める前に作った要件定義書と設計書を紹介します。「小さなツールに本当に必要なのか」「どのくらいの分量で書けばよいのか」は、学習を始めたときに私自身が迷ったところでした。実際に書いた内容を、ほぼそのまま載せます。
題材選び:検査値の単位換算ツール
Step 1 の題材は、血液検査の値の単位を換算するツールにしました。
血液検査の値は、使う単位が国や資料によって違います。日本の検査結果では、血糖値などを mg/dL(デシリットルあたりのミリグラム)で表すことが多いのですが、海外の資料では mmol/L(リットルあたりのミリモル)などの SI 単位が使われます。自分の値を海外の資料と見比べようとすると、単位をそろえる必要があります。
この題材を選んだ理由は2つです。
- Step 1 で学ぶことが一通り詰まっている:
入力欄と選択肢、計算、結果の表示、入力の誤りへの対応と、画面づくりの基本がちょうど収まる規模です - 最終目標につながる:
「検査項目」「値」「単位」という組み合わせは、最終目標の血液検査アプリでもそのまま使います。ここで作った計算部分は、後のステップでも使い回せます
ご注意:このツールは Web 開発の学習を目的としたものです。医療的な判断には使わないでください。検査結果の解釈や健康上の判断は、必ず医師にご相談ください。
要件定義書:何を作るかを決める
要件定義書は、次の6つの項目で構成しました。すべてのツールで同じひな形を使っています。
| 項目 | 書くこと |
|---|---|
| 1. 目的 | このツールで何ができるようになるか、学習のねらい |
| 2. 利用者と利用場面 | 誰が、どんなときに使うか |
| 3. 機能要件 | できること(F-01、F-02 … と番号を振る) |
| 4. 非機能要件 | 性能、セキュリティ、対応ブラウザなど(N-01 …) |
| 5. 対象外 | 今回はやらないこと |
| 6. 受け入れ条件 | 何ができたら完成か |
機能要件と非機能要件
今回の中身は、次のとおりです。
| 番号 | 内容 |
|---|---|
| F-01 | 検査項目を選択できる(血糖、総コレステロール、中性脂肪、クレアチニン) |
| F-02 | 数値を入力できる |
| F-03 | 換算の向きを選べる(mg/dL → SI 単位、またはその逆) |
| F-04 | 入力するとすぐに換算結果を表示する(ボタン不要) |
| F-05 | 数値以外・負の値・空欄のときは、結果の代わりにメッセージを表示する |
| N-01 | 計算はブラウザ内で完結し、入力値をサーバーへ送らない |
| N-02 | 決められた URL で、認証をかけて使う |
| N-03 | PC の Chrome / Edge と、スマホのブラウザで崩れずに使える |
| N-04 | 結果は小数点以下2桁で表示する |
番号を振っておくと、設計書やテスト項目から「どの要件に対応するか」を短く書けます。組み込みの仕様書で、要求に ID を振ってトレーサビリティを取るのと同じ考え方です。

図の右側のテスト項目の番号(S-01 など)は、確認の種類ごとに付けた番号です。テスト項目書の書き方は、第8回で紹介しています。
N-01 の「入力値をサーバーへ送らない」は、検査値という個人の健康情報を扱う題材なので、あえて明記しました。今回のツールでは計算がブラウザで完結するため、送る必要がそもそもありません。
対象外を書く
意外に役立ったのが「対象外」です。今回は次のものを、はっきりやらないと決めました。
- 結果の保存と履歴の表示
- サーバー側の API とデータベース
- 上の4項目以外の検査項目
- 医療的な判断(学習用のツールであり、診断には使わない)
作っている途中で「保存もできたら便利かも」と思っても、ここに書いてあれば迷わずに済みます。保存やデータベースは、ロードマップの後のステップで学ぶ予定なので、そちらに任せます。
受け入れ条件
最後に、完成の基準を3つ決めました。
- 決められた URL で、認証の後に画面が表示される
- 4項目それぞれで、両方向の換算が手計算と一致する(例:血糖 100 mg/dL → 5.55 mmol/L)
- 異常な入力でメッセージが出て、エラーで止まらない
要件定義書全体の分量は、A4 で1ページ強です。AI に下書きを出してもらい、それを手直しする形で書きました。
設計書:どう作るかを決める
設計書は、次の7つの項目で構成しました。こちらもひな形は共通です。
| 項目 | 書くこと |
|---|---|
| 1. 全体構成 | ブラウザからサーバーまで、どこを通って何が動くか |
| 2. 公開パス・ポート | URL、待ち受けポート、Web サーバーの設定ファイル名 |
| 3. 画面設計 | 画面の部品と、それぞれの動き |
| 4. API 設計 | サーバーとのやり取り(今回はなし) |
| 5. データ設計 | 扱うデータの項目と型 |
| 6. ディレクトリ構成 | ファイルの置き場所 |
| 7. 要件との対応 | F-01 などの要件を、どこで実現するか |
全体構成と公開パス
経路は第1回で紹介した構成と同じで、ブラウザ → Cloudflare → Apache → Node.js の順に届きます。公開パスは /apps/unitconv/、ポートは 5002 です。
Step 0 と大きく違うのは、計算をブラウザで行う点です。サーバー(Node.js)は、画面のファイルをブラウザに送るだけで、計算には一切関わりません。
画面設計
画面は1枚だけです。部品ごとに、HTML の要素と、プログラムから見分けるための名前(id)を決めました。
| 部品 | HTML の要素 | id | 動作 |
|---|---|---|---|
| 検査項目 | select(選択肢) | item | 4項目から選ぶ(F-01) |
| 換算の向き | select | direction | mg/dL → SI 単位、または SI 単位 → mg/dL(F-03) |
| 入力値 | input | value | 数値を入力する(F-02) |
| 入力の単位 | span(文字の表示) | in-unit | 項目と向きに合わせて単位を表示する |
| 結果 | output(結果の表示) | result | 換算結果を小数2桁で表示する(F-04、N-04) |
| メッセージ | p(段落) | message | 入力に誤りがあるときに理由を表示する(F-05) |
id は、プログラムから画面の部品を探すときの名札です。組み込みでいえば、レジスタに付けた名前にあたります。後でプログラムを書くとき、この表をそのまま見ながら書けました。
データ設計:換算テーブル
換算に使う係数は、表の形で設計書に書きました。プログラムでは、これを定数のテーブルとして持ちます。C でいう const の構造体配列です。
| id | 検査項目 | SI 単位 | 係数(SI 単位の値 = mg/dL の値 × 係数) |
|---|---|---|---|
| glucose | 血糖 | mmol/L | 1 / 18.016 |
| tchol | 総コレステロール | mmol/L | 1 / 38.67 |
| tg | 中性脂肪 | mmol/L | 1 / 88.57 |
| cre | クレアチニン | µmol/L | 88.4 |
計算は「SI 単位の値 = mg/dL の値 × 係数」に統一し、逆向きは係数で割るだけにしました。項目ごとに掛けるか割るかを変えると、間違いのもとになるからです。
ディレクトリ構成
ファイルの置き場所も、書き始める前に決めておきました。
unitconv/
├── docs/ 設計書類
├── index.html 画面(ビルドの入口)
├── src/
│ ├── main.ts 画面の処理(イベント・表示)
│ ├── conv.ts 換算テーブルと計算(画面に依存しない)
│ └── server.ts 画面のファイルを送るだけのサーバー
├── dist/
│ ├── server.js server.ts のビルド結果
│ └── public/ 画面のビルド結果
├── tsconfig.json ブラウザ用の TypeScript 設定
└── tsconfig.server.json サーバー用の TypeScript 設定要件との対応
最後に、要件の番号ごとに、どこで実現するかを並べました。
| 要件 | 実現する場所 |
|---|---|
| F-01 | 画面の item / conv.ts の換算テーブル |
| F-02 | 画面の value |
| F-03 | 画面の direction / conv.ts の計算関数 |
| F-04 | main.ts のイベント処理 → result に表示 |
| F-05 | main.ts の入力チェック → message に表示 |
| N-01 | サーバーとのやり取りなし。計算は main.ts と conv.ts |
| N-02 | Apache の中継設定と Basic 認証 |
| N-03 | 画面の見た目の設定(CSS) |
| N-04 | conv.ts で小数2桁に整える |
この表があると、作り忘れがないかを最後に確かめられます。テストのときも、「F-05 を確かめるなら main.ts の入力チェックを見る」と、すぐにたどれました。設計書全体の分量は、A4 で2ページほどです。
設計で決めた大事なこと
表には現れにくいものの、設計の段階で決めておいてよかったことが3つあります。
1. ブラウザだけで動くツールでも、配信は Node.js にする
今回のツールは、計算をすべてブラウザで行うので、サーバー側のプログラムは本来いりません。画面のファイルを Apache から直接配る方法もあります。
それでも、Step 0 で決めた「Apache は Node.js へ中継するだけ」という方針に合わせて、画面のファイルを送り返すだけの小さな Node.js サーバーを置くことにしました。こうすると、常駐(PM2)、中継(Apache)、認証の設定が、Step 0 とまったく同じ形で済みます。ツールごとに配り方が違うと、運用の手順もツールごとに変わってしまうからです。
組み込みでいえば、アプリの中身は違っても、ブートローダと書き込み手順は全製品で共通にしておくようなものです。
2. ビルドの出力先を分ける
このツールには、性質の違うプログラムが2つあります。

| 画面のプログラム | サーバーのプログラム | |
|---|---|---|
| 動く場所 | 利用者のブラウザ | 自宅サーバーの Node.js |
| 元のファイル | main.ts、conv.ts | server.ts |
| ビルドの道具 | Vite | tsc |
| 出力先 | dist/public/ | dist/server.js |
同じ TypeScript でも、ビルドの道具も、使える機能も違います。ブラウザ用のコードには画面の部品を操作する機能が、サーバー用のコードにはファイルを読む機能が必要です。そこで、TypeScript の設定ファイルも2つに分けました。
組み込みでいえば、同じリポジトリにブートローダとアプリが入っていて、それぞれ別のリンカスクリプトとコンパイルオプションでビルドする状態です。
3. 計算と画面を分ける
換算の計算(conv.ts)と、画面の操作(main.ts)を、別のファイルに分けました。conv.ts は画面のことを一切知らず、「値と項目と向きを受け取って、計算結果を返す」だけです。
こうしておくと、計算部分だけを単体で確かめられます。実際、画面を作る前に、conv.ts だけで4項目の換算が手計算と一致することを確認しました。また、最終目標の血液検査アプリでも、conv.ts はそのまま使えます。
ハードウェアに依存しない演算処理を、ドライバ層から切り離しておくのと同じ考え方です。
つまずいたこと
保存し忘れて、空の設計書をコミットしていた
設計書を書いて Git に記録(コミット)したつもりが、後で調べると、中身が空のファイルが記録されていました。VS Code でファイルを作って内容を貼り付けたものの、保存する前にコミットしていたのです。
気づいたのは、次の作業でコミットしたときに、触っていないはずの設計書が「変更あり」と表示されたからでした。差分を確かめると、次のような表示になっていました。
diff --git a/docs/02_設計.md b/docs/02_設計.md
index e69de29..3a4dfd7 100644e69de29 は、Git で「空のファイル」を表す決まった番号です。つまり、前のコミットの時点ではファイルが空だった、ということです。組み込みでいえば、エディタのバッファをディスクに書き出し忘れたまま、ビルドしてしまったような状況です。
実害はありませんでしたが、それからは次の2つを習慣にしています。
- コミットの前に、VS Code のタブに未保存の印(●)が付いていないかを見る
- コミットの前に
git statusで、今回のコミットに入れるファイルの一覧を確かめる

確かめるためのコマンドは、次のとおりです。
$ git status # 変更のあるファイルの一覧
$ git ls-tree -l HEAD docs/ # 記録されたファイルの大きさ(0 なら空)設計を変えるときは、先に設計書を直す
作っている途中で、設計を足したくなる場面が何度かありました。たとえば、選択肢にプログラム用の内部の値(glucose など)を付けることにしたときや、サーバー用の設定ファイルを1つ増やしたときです。
そのたびに、先に設計書を直してから、プログラムを直すようにしました。順番を逆にすると、設計書がいつの間にか実物と合わなくなり、後で見返したときに役に立たなくなるからです。組み込みの現場で、仕様変更のたびに設計書の改版を先に回していたのと同じです。
まとめと次回予告
小さなツールでも要件定義書と設計書を書いてみて、感じたことをまとめます。
- 分量は、要件定義書が A4 で1ページ強、設計書が2ページほど。共通のひな形があれば、負担は大きくない
- 「対象外」と「受け入れ条件」を書くと、作っている途中で迷わない
- 画面の部品の id や換算の係数を表にしておくと、プログラムを書くときにそのまま使える
- 要件に番号を振り、設計とテストからたどれるようにしておくと、作り忘れや確かめ忘れに気づける
Web の技術は初めてでも、「何を作るか」「どう作るか」を先に決めるやり方は、組み込みで身につけたものがそのまま使えました。むしろ、知らない技術を扱うときほど、道しるべとして役に立つと感じています。
次回は、Step 1 で初めて使った Vite(ヴィート)というツールを、組み込みの言葉で読み解きます。ブラウザ用のプログラムを「コンパイルしてリンクする」道具でありながら、書き込みのたびに自動で画面を更新してくれる、デバッガのような顔も持つツールです。
この記事は、シリーズ「組み込みエンジニアの Web 開発入門」の1本です。ほかの回は、シリーズの目次からどうぞ。



コメント