仕様書の書き方と使い道について

# 概要
最近無駄な仕様書を見かけることが多いので,仕様書の作成方法を考えてみた.  
考える上で必要なことは以下である.  

 - 何のために必要か？
 - 要点
 - 活用する方法

# 仕様書は何のために必要か？
仕様書は,**コーディングする前の何を作るかを明確にする書類**である.  
これは,一人開発においても,他社間での開発でも言えることだが,作業が進むにつれて自分が何を作っているか分からなくなるものである.その結果,思ったものと違う出力をしたり,先方(相手の会社)で使用できないということが起こりうる.  
それをなくすために,**どのような機能で,何ができるのか**を明確にすることが目的である.  

https://e-words.jp/w/%E4%BB%95%E6%A7%98%E6%9B%B8.html

> 一般的には仕様書には「何を作るか」（what）を記し、「どのように作るか」（how）は記さない。

こちらにもあるように,どのように実現したか,という部分は必要ない.  

# 要点
ずいぶん抽象的で結局何が必要なんだかわからない.ということで,ITエンジニアとして必要な仕様書の要点をまとめる.  
ただしケースバイケースで,先方が仕様書のフォーマットを指定してきたり,以下の例が当てはまらない(非効率的な)例も存在するため,注意が必要.  

## 例 : ログイン認証仕様書

まず大事なのが,どういう合意で開発が始まったかである.  
ログイン認証にもさまざま存在し,メールアドレスとパスワードだけのシンプルなものや,Google認証の利用,AppleStore認証の利用,二要素認証等々,どのような使用にするか,先方と相談する必要がある.  
先方の態度次第では,そこも決まらない場合があり,プログラマ自身で決定する機会もあるだろう.  

今回は,先方から以下の条件で開発してください.と来ているものとする.  

> ユーザーがユーザー名とパスワードでログインできるようにしてください.  
> 成功したら「ログイン成功」
> 失敗したら「ログイン失敗」
> と画面に出すようにしてください.

プログラマ的にはかなりアバウトです.  
理由として以下が挙げられます.  

 - ユーザー名の定義が無い(2文字以上8文字以下,半角英数字のみ,かぶり無し)
 - パスワードの定義が無い(8文字以上20文字以下,半角英数字特殊記号(省略),特殊条件なし)
 - エラーケースが存在しない(サーバーに接続できない場合,ログイン失敗とも表示できない)
 - ユーザー名とパスワードが格納されている場所がわからない.(今回はDBが存在する)

等々

カッコ内の条件は,先方と相談しながら実装していくのもあり,**実装コスト**を見つつ,検討していくのがよい.  
これらを定義しないことによる問題はいくつか存在する.  
例えば,ユーザー名の長さを無限にし,入力文字制限を無しとする.  
そうすると「SQLインジェクション」をされる可能性が出てくる.  

https://www.nttpc.co.jp/column/security/sql_injection.html

また,上記では定義されていないが,ユーザー名を1文字で実行した場合,どのような表記になるか,パスワードを21文字で実行しようとしたときどうなるか,などが書かれていないため,詳細な実装できない.一般的なのは,クライアント側での実装になるので,今回は実装しないとし,詳細な設計は書いていない.  

では実際に,設計書を書いてみよう.  

```
# 設計書
## 概要
プロジェクトID : 1234
資料作成 : 田中太郎 20230921
ReactServerとMysqlDBを用いて,Json形式のユーザー情報から,認証を行い,成功か失敗かを返す.  
実装先は`app/pages/auth/login.ts`  
DB接続先は`DatabaseX users テーブル`である.


## 入力と出力
入力値と,出力値について説明する.  
デバッグ環境では`localhost:3000/auth/login`にアクセスすることで確認できる.  
### 入力
{
 id:ab123,
 password:abcd1234
}
id : Integer 8文字以下
password : String 20文字以下
### 出力
code : Integer 別途codeリスト参照(※参照先記入)
msg : レスポンスメッセージ
成功の場合
{
code : 200,
msg : "成功"
}
失敗の場合
{
code : 200,
msg : "失敗"
}
エラーケース
{code : 1000}  // サーバーにアクセスできない.
{code : 1001}  // データベースにアクセスできない.
※ 以下必要であれば追加
{code : 1002}  // ユーザー名が不適切(例えば1文字以下や特殊文字が使用されているなど)
{code : 1003}  // パスワードが不適切(例えば入力されていないや特殊文字が使用されているなど)
```

上記のように code 1002,1003を追加しておくと,仕様変更に対応できる.  
例えば,ログインできない場合に,ユーザー名パスワードの入力ルールを表示したい,などの場合に活用できる.

文面的にはこれくらいでいいが,中身の詳細が足りない.  
実際にどのような作業を行っているか簡単に書き記す必要がある.  

簡単な処理の流れは,シーケンス図を用いるとよい.  

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1505183/6631783e-4ce7-aefb-0db9-4b2f570cdd95.png)

こちらは`PlantUML`を使用して作成している.  
使い方は各自別途検索してほしい.  
VSCodeでプラグインを用いて作成することをお勧めする.  

本来であればもう少し複雑で,エラーケースを書いたり,パスワードのエンコード,デコードを行う処理が入ったりするが,基本的には**外部との接続方法**がしっかり書かれてくれていればよい.  

もうちょっとしっかり書くとこんな感じ.エラーケースがどのタイミングで発生するのかがわかりやすい.  

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1505183/49a00c5d-e77d-bb30-2db4-fe15b993e0ff.png)

<details><summary>サンプルのplantUMLコード</summary>

```
@startuml
title : ログイン認証
' 現状の実装
participant クライアント As client
participant Webサーバー As server
participant データベース As database

== 現状の実装 ==

client -> server: ユーザーID,パスワード
server --> client: サーバーへの接続ができない場合{code:1000}
server -> database: DBへのConnection確立
database --> server: 接続確認
server --> client: DBへの接続ができない場合{code:1001}
server -> server: passwordのハッシュ化
server -> database: SQL,EXSIST文実行
database --> server: 成功or失敗
server -> database: 接続の解除
server -> server: 失敗時,原因を調査し,msgを作成
server -> server: リソースのJson化
server --> client: {code:200,msg:成功or失敗}

@enduml
```

</details>

これらの情報が,仕様書に必要である.  

# 活用する方法

そもそもなんで仕様書なんて作成するか.理由は4つある.  

 - **仕様が固まっていないと実装できない**ため.
     - 実装を開始するには,先方の意図をくみ取り,条件のすり合わせをしておく.
     - また,書いておくことで別の誰かに作業を委託できる.
     - 仕様書を作成していく中で,実装に必要な条件が見えてくることもある.
 - **成果物として提出する**ため.
     - めちゃくちゃアホらしい話だが,先方は読みもしない仕様書の提出を求めることがある.
     - 仕事しました,という報告のために必要な模様
 - 機能を使用する人が**入出力を確認する**ため
     - この機能を使うための概要と入出力さえあれば,中身が何であれ使うことはできる.
     - 重要なことは,各入出力のフォーマットが定義されていることにある.
 - その機能で**エラーが出現したときの,対処方法**を残すため.
     - エラーが起きたときの原因究明に役に立つ.
     - 実装した機能が原因なのか,コードが間違っているのか,エラーコードが存在すれば容易にわかる.

上記のように,コードを見なくても,必要な情報が手に入る状態が望ましい.

# 最後に

もうちょっと例を出したい感じもあるので,要望があれば追記する.