SpecMD - Wordによる仕様書地獄からの解放
この記事は VSCodeの拡張機能 SpecMD(Markdown) の布教記事です。
ツールの詳細だけ読みたい方はこちらからどうぞ。
目次
はじめに
何を隠そう私はWordが嫌いです。できる限りWordから離れて生きてきました。大学ではTeXを使ったし、プライベートではMarkdownを使っています。
しかし、仕事をしているとそうも言っていられず、絶対と言っていいほど仕様書はWordで作られています。100ページ以上あるWordを5つ、6つ開いて、ここでもないそこでもないと、パズルのピースをはめるように修正したり、調査したりする日々です。
最近この非効率な作業が耐えられなくなってきました。この恨みつらみと共に、布教の意味も込めて記事を書きます。
たしかに、「誰でも使える」というのはWordの大きなメリットです。
しかし、Wordに固執し続けた結果、開発現場はどうなりましたか?
現場で何が起きているか
パターン1:1冊に全部まとめる
例えば、こんな話。
最初は商品Aの仕様書でした。シンプルな一冊のWord文書。
そのうち次世代モデルBが出ます。「Aと共通部分多いし、同じファイルに追記でいいか」
続いてCが出ます。追記。
今度は大型に改造したDをリリースすることになりました。DはA,B,Cの優れた機能を引き継いでさらに機能追加もされます。さあ、どうする?「該当箇所に『※Dを除く/※Dで使用』って注釈入れとけばいいか」
さあ、あなたは新規参入者です。Dの仕様を知りたい。
この仕様書、読めますか?
言葉で聞くと意外といけそうに思えます。でも、ベン図で表現するとその凶悪さがわかります。
A/B/C/Dそれぞれに固有の仕様があり、同時に共通部分もあります。これを1冊にまとめると、あらゆる箇所に「※Xを除く」「※Yのみ」という注釈が散りばめられることになります。
どこがDに該当する記述で、どこがDには関係ない記述か、判別できる自信はありますか?
おそらく無理です。この仕様書は多くの開発者がその場しのぎで継ぎ接ぎしてきました。もう、どの商品の仕様なのか追うことすら難しい箇所があるはずです。
そして最悪なのは、読むときの認知負荷。
Dの仕様を調べているのに、目に入ってくるのはA/B/Cの情報ばかり。「これはDに関係あるのか?」を常に判断しながら読み進めなければなりません。本来、仕様を理解することに使うべき脳のリソースが、関係ない情報のフィルタリングに消費されます。
仕様書を読むたびに、別の製品の仕様に踊らされる。これが毎日続きます。
修正するとなったときは、もうそれはジグソーパズルのピースを似ている場所に無理やり押しはめることになるでしょう。
パターン2:コピーして分割する
もしくは、こんな話。
最初はシリーズAの仕様書。これは綺麗にまとまっていました。
しばらくして類似のシリーズBが出ることになりました。「Aとほぼ同じだし、コピーして差分だけ直せばいいか」。B用の仕様書を新規作成。多少同じような記述があるけど、まあ仕方ない。
次世代のCが出ました。AともBとも微妙に違います。また新規作成。
ここで問題が起きます。Aの認証機能にバグがありました。改修に伴い仕様変更。A/B/C全部に同じ認証機能があるから、全部の仕様書を直さないといけません。
直しました。はずでした。
半年後、「Bの認証の仕様、ドキュメントと実装が違うんですけど」
「全部直した」が「全部直ってなかった」になります。 維持コストはすぐに莫大になって保守されなくなります。
パターン3:共通化したつもり
上のパターンを経験して、こう思います。
「共通部分を括り出して、別のWordにまとめておくべきだった」
でも、それをやるとどうなるか。
シリーズDの仕様を把握したい。
- シリーズD_仕様書.docx を開く
- 「認証については共通機能_認証.docxを参照」→ 開く
- 「APIについては共通機能_API.docxを参照」→ 開く
- 「データ形式については共通機能_データ定義.docxを参照」→ 開く
- 「エラーコードは共通機能_エラー定義.docxを...」
気づけばWordを5個も6個も開いています。仕様書は無数に増えていきリンクも増えていきます。そして増え続けたリンクは開かないと読めないから、見ないことも多くなります。やがてリンクのパスはどこかに消えて、新規参入者は圧倒的な仕様書の中から何を手掛かりにものを考えれば良いかわからなくなります。
PCは重くなり、タスクバーはWordだらけ。
コードならIDEが参照先を自動解決して、ジャンプ一発で飛べます。
Wordにはそれがありません。
コードに置き換えると一発でわかる
プログラマーなら、この問題の本質がすぐわかるはずです。
| パターン | コードで言うと | 評価 |
|---|---|---|
| 1冊にまとめる | mainに全部ベタ書き | アンチパターン |
| コピーして分割 | 共通処理をコピペ | アンチパターン |
| 別ドキュメントに分離 | 関数抽出したけどIDEがない。参照先がないこともざら | 惜しい |
コードなら正解は明確です。
共通ロジックを関数に抜き出して、各所から参照する。
初めに何の製品か入力を与えてやれば、必要のない仕様は分岐を作って参照しなければ良い。
変数を使って用語を定義できると、用語の定義変更のたびにgrepを繰り返さなくて良い。
仕様書でも同じことをすればいいんです。
なのに、なぜか仕様書になると、熟練のプログラマーでさえ何も考えずにWordに甘えてしまいます。
コードでは絶対にやらない設計を、仕様書では平気でやる。
「仕様書だから仕方ない」
「Wordってそういうものでしょ」
「今までずっとそうしてきたし」
その結果莫大に成長した仕様書は負債となって開発者を苦しめます。
そもそものWord自体の問題
仕様書管理の問題だけじゃありません。Word自体にも問題があります。
重い
仕様書が育って数百ページを超えると、Wordが悲鳴を上げ始めます。
スクロールがカクつく。検索が遅い。保存に時間がかかる。画像が多いとさらに絶望的。
「ちょっと確認したいだけなのに」が、毎回ストレスになります。
注力すべき点がズレる
本来、仕様書で大事なのは仕様の中身です。
なのにWordを使っていると、気づけばこんなことに時間を使っています。
- 見出しのスタイルが崩れた、直さなきゃ
- 表が次のページにまたがって変になった
- 画像の位置がずれた、アンカー設定どうなってる?
- 目次の更新を忘れてた
- フォントが統一されてない箇所がある
体裁の調整に注力して、肝心の仕様を書く時間が削られる。
これは本末転倒です。
なぜMarkdownなのか
「Markdownなんて覚えられない」は誤解
Markdownの基本構文は30分で覚えられます。
-
#で見出し -
-で箇条書き -
**太字**で強調
これだけです。Wordの「スタイル」「アンカー」「セクション区切り」を理解するより遥かに簡単です。
しかもMarkdownはプレーンテキストなので、メモ帳でも読めます。特別なソフトがなくても内容を確認できます。10年後にファイルが開けなくなる心配もありません。
「でも納品物はWordじゃないとダメなんだけど」
安心してください。Markdownで書いた文書は、最終的にWordやPDFに変換できます。
Markdownはあくまで書くときのフォーマットです。納品時にはPandocなどのツールを使えば、Wordファイルとして出力できます。つまり、書く効率と納品形式は両立します。
「社内ではMarkdown、社外にはWord」という運用が可能です。
チーム開発との相性
Wordでチーム開発したことがあるなら、こんな経験があるはずです。
- 「最新版どれ?」→
仕様書_v2_最終_本当の最終.docx - 「誰がどこ直した?」→ 変更履歴を追うのが地獄
- 「同時に編集したい」→ 競合してファイルが壊れる
MarkdownならGitで管理できます。
- 履歴管理:誰が・いつ・何を変えたか、全て記録される
- 差分比較:行単位で変更箇所がわかる
- ブランチ運用:本番に影響を与えず、並行して修正できる
- レビュー:プルリクエストで仕様変更をチームで確認できる
コードと同じワークフローで仕様書を管理できます。
解決策:SpecMD
Markdownで仕様書を書けば、Wordの問題のいくつかは解決します。
しかし、素のMarkdownでは足りない部分があります。冒頭で挙げた「1冊にまとめる問題」「コピペ問題」を根本的に解決するには、プログラミングの概念が必要です。
- 変数 → 共通の値を一箇所で管理
- 条件分岐 → 製品ごとの差分を出し分け
- インクルード → 共通部分を別ファイルに抽出して参照
これらをMarkdownで実現するのがSpecMDです。VS Code拡張として提供されています。
SpecMDで何ができるか
SpecMDを使うと、書くときも読むときも認知負荷が激減します。
- 書くとき:注目している製品に関連のある仕様だけがハイライトされ、どこに仕様を追記すべきかすぐにわかります。前の例で言うとDの製品について仕様書を追記したいとき、関係のない仕様はグレーアウトされます。さらに変数を使用できるので仕様や用語の変更にも強いです。
- 読むとき:設定を切り替えれば、注目している製品だけの仕様書をクリーンに出力できます。前の例で言うとDに関係のない仕様は表示させないことができます。
具体的に見ていきましょう。
変数で共通値を管理
# config.yaml
productName: "Widget Pro"
voltage: 200
# ${productName} 仕様書
動作電圧: ${voltage}V
製品名を変えたい?ハードウェアの出力仕様が変わった?config.yamlを1箇所直すだけ。全ての参照箇所に反映されます。
用語の定義変更のたびにgrep→置換を繰り返す必要はありません。
以下のGIFで、config.yamlの変数がMarkdownに即座に反映される様子を示します。
条件分岐で製品別に出し分け
直感的なif文が使えます.
@x > y
x is bigger than y
@elif y > x
y is bigger than x
@else
x equals y
@end
エディタ上で、有効なブロックは緑、無効なブロックは灰色で表示されます。 今見ている製品・バージョンに関係ない仕様は視覚的に消えます。Dの仕様を調べているときに、A/B/Cの記述に踊らされることがなくなります。
設定ファイルを切り替えるだけで、その製品だけのクリーンな仕様書が出力されます。他の製品の情報が混ざることはありません。
switch文も使えます。
@switch gradeLevel
@case 1
## Basicプラン
基本機能のみ。
@case 2
## Standardプラン
基本機能+分析機能。
@case 3
## Proプラン
全機能+API連携。
@end
共通部分をインクルード
# 製品仕様書
@include ./common/header.smd
@include ./common/safety.smd
## 製品固有の機能
(ここに製品固有の内容)
@include ./common/footer.smd
共通部分は別ファイルで管理。認証機能を修正したら、参照している全製品の仕様書に自動で反映されます。
「全部直したはずだった」が起きません。
インクルード先はCtrl+クリックで直接ジャンプできます。Previewからセクションを押してもソースに飛べます。Wordを5個も6個も開く必要はありません。IDEと同じ体験です。
その他の機能
- インライン値表示 → 変数の現在値がエディタ上に表示される
- ライブプレビュー → Alt+Dで変換後のMarkdownを確認.右クリックからも表示可能
- 定義ジャンプ → 変数やインクルードをCtrl+クリックで定義元へ
-
入力補完 →
${で変数候補、@で構文候補を表示 - オープンソース → ソースコードが公開されているので安心
まとめ
プログラマーなら絶対にやらない設計を、仕様書では強いられてきました。
SpecMDを使えばまるでコードを書くように,仕様の切り分けができるようになります.
仕様書にも、プログラミングの知恵を。
使ってみてね.




