ヘッダファイルという名の仕様書

以下の文章を書いていたときは、まだgitを使っていなかった時期のものです。
以下の文章でSVNで記載してある部分は、gitを使うやり方に読み替えて参考にしてください。

----
私が経験したことのある仕様書の作成方法は、C++のヘッダファイルとして仕様を共有するというものがあった。

これは複数の部署にまたがる10数名の開発チームの中でうまく機能した。
このとき、複数の部署で開発を分担するときのそれぞれの仕様のうち、外部仕様書に相当する部分をJavaDocスタイルのドキュメンテーションコメントが詳細に書かれたヘッダファイルを共通に用いた。（また、それ以外のドキュメントも併用していた。)
以下に述べる仕様書は実装仕様書のレベルにまでブレークダウンした後の議論です。

#### **ヘッダファイルという名の仕様書の仕組み**
・バージョン管理システムSVN　(http://tortoisesvn.net/)
・ドキュメンテーションコメントの記入
・Doxygen　（解説ページ　http://www.doxygen.jp/)
バージョン管理システムSVNを用いて常に最新のコードを共有できるようにして、ヘッダファイルからDoxygenでドキュメントを生成する。
公開して共有するAPIをヘッダファイルとして明確に書く。
変数名自体が十分なドキュメントになるように変数名を工夫する。例：angleという引数よりはdegreeの方が角度の単位が何なのか迷わなくていい。
const修飾子を引数につけるなど、C/C++のコード自体の中で意味が明確になる記述を選ぶこと。const修飾子が関数の引数に書いてあれば、わざわざ@param[in]を書かなくても意味は明確になる。
（また、const修飾子をつけてある引数の値が関数の中で変更されていれば、コンパイル時にエラーを生じるので、間違いを見つけやすい。）
そのような努力をした上で、Doxygenのためのドキュメンテーションコメントは、関数・メソッドの引数を@param[in], @param[out], @param[in,out]のどれであるのかを明言するように書く。

#### **その利点**
ヘッダファイルを仕様書にすることは次のような利点を持つ
・ソースコード中のヘッダファイルをバージョン管理システムでupdateすれば、常に最新版のメンテナンスされた仕様が反映される。
・ドキュメンテーションコメントの書き方が標準化されているので、だれが書いても書き方の差が少なくなる。
・ExcelやWordで記述するのと違って、改版の内容の差分を確認しやすい。
・ヘッダファイルはテキストファイルなので、文字検索のツール類を使って、目的の検索を自在に行いやすい。


>ヘッダファイルと仕様書が別々であるよりも、ヘッダファイル中に仕様書を組み込んでしまった方が、メンテナンス性は向上するはずだ。この方法は、『人月の神話―狼人間を撃つ銀の弾はない (Professional Computing Series)』の第15章「もう一つの顔」で言及されている「自己文書プログラム」の考え方に近い。
[よいコメントの書き方入門（心構え編）](http://d.hatena.ne.jp/eel3/20090811/1249977594)


#### **PDFの作成**
部署の方針により、wordの種類やpdfファイルで仕様書を作成するには、以下の記事が参考になります。

Doxygenで綺麗な日本語の納品用PDFを出力する方法
(http://uenoshin.hatenablog.com/entry/2014/05/22/104234)

Doxygenから奇麗なPDFで出力する方法
(http://qiita.com/BugDig/items/27192e033f364019d6a4)


#### **設計のチェック：ヘッダファイルだけのソリューションのビルド**
ヘッダファイルだけからなるソリューションを作って、その範囲でビルドしてみる方法がある。もちろん、実装が存在しないのでうまくいくはずはない。それでも文法上の問題が生じることがあって、データ構造の定義や、関数の定義に間違いがあることを指摘してくれるという効果がある。
　しかも、Doxygenを使うと、複数のデータ構造間の関係をクラス図で表示させることができる。クラス間の設計の妥当性を検証することもできる。
　コンパイラ、Doxygenというツールは、ヘッダファイルの範囲でも設計の妥当性を検証してくれる貴重なツールと考えることができる。

#### **明確に書く努力：**
　仕様書となるヘッダファイルを書く際には、明確に書く努力を続けることが必要だ。その言葉が、どういう使われ方をしている言葉か考えて、誤解を生じにくい表現を選ぶようにすること。
　その部分を理解するには、その部分に書かれている内容で十分なことを目指すこと。

#### **付記：**
　WordやExcelファイルで記述されている仕様書の内容を、現在のソースコードに反映されているかどうかをチェックする効率的な方法はありますか？　それが見当たらないので、ヘッダファイルを仕様書にしようと提案するのです。
 ヘッダファイルで必要十分な内容が記述されていれば、OSにかかわらず必要な情報を読めます。Windowsのofficeアプリで書かれた仕様書は、Linux環境では読めないと思っておいたほうがいいでしょう。Linuxアプリを開発するときに、その隣にWindowsマシンがあってofficeアプリの内容を見ることができるだけのディスプレイとキーボードはないと思うべきでしょう。ですから、**必要十分な内容はLinux上でヘッダファイルで読めるようにしておく**ことを強く推奨します。

Excelのシートからデータを取り出す方法：

Excelが基本となるファイルであって、しかもそのExcelファイルの記述の形式が安定している場合には、そこからデータを取り出すことも考える価値がある。一例として、Pythonを使ってExcelファイルからデータを読み出すことができる。
完全に自動化できていなくても、ベースとなったドキュメントが更新されていれば知ることができるように、ドキュメントの最新の日付の変更をチェックできるスクリプトを書いておけば、まだましだ。バージョン管理されていない場所に仕様のドキュメントがある場合には、そのような方法で変更に気づけるようにしておくのがいいのだろう。


[Excel読み込み (xlrd)](http://www.python-izm.com/contents/external/xlrd.shtml)


####**追記：**
　SVNをWinMergeと組み合わせて使っています。WinMergeは実は、画像どうしの比較をして、違っていると画像を両方表示するという機能をもっています。テキストで書けないことを画像ファイルで書いておいて、それを比較するということも可能ではあるらしい。


#### **運用上の注意：**
　実装の内部設計書の提供をDoxygenで生成したドキュメントでよいとして外注先に依頼する場合には、きちんと必要な内容が記述されているかに注意してください。ドキュメンテーションコメントがしっかり書かれていないソースコードからでもDoxygenはドキュメントを作成します。@brief, @param[in], @param[out]などを書けばいっけんそれっぽいドキュメントが生成しますが、それだけでは仕様書にするには不十分なものです。
　そのシステムの使われる重要な概念について、**明確な言葉の定義を述べる必要があります**。そのように設計していることが妥当であることを仕様書は明確に示すことです。
　物理量の場合には単位が必須です。
設計・実装が適切であることをテストするための枠組みの意味のまとまりを作っておくことです。その意味のまとまりはクラスや名前区間を用います。そうするとそのまとまりに対してテストしやすくなりますし、その意味のまとまりを仕様書においても示すのが有効だと考えます。

クラス図の作成に関する記事
ドキュメント自動生成ツールDoxygenの設定
http://demura.net/tukuba-challenge/7067.html

テキストから UML を生成する PlantUML についての解説記事
http://yohshiy.blog.fc2.com/?tag=Doxygen

ブロック図生成ツール blockdiag
http://blockdiag.com/ja/#

#### **追記：開発中のコードへの後決めの仕様書**
 コードの記述の前にヘッダファイルでの外部仕様書を実現できなかった場合でも、ヘッダファイルの重要性は失われません。
　既に実装がされているコードでも、ヘッダファイルは、そのモジュールがどういう外部仕様を満たすべきかを記載されていなければなりません。また、そのモジュールを**単体テストするのに十分な明快さ**を持っていなければなりません。もし、そうなっていなければ、そのモジュールの責任者に納得のいくまで、不明点を聞いて解き明かして、ヘッダファイルにドキュメンテーションコメントを書いて、第三者が理解できるものにします。

### **追記：間違えやすい項目**
　右・左の定義：例　写真の人物の顔で、左の目というときに、画像のx座標の小さいほうを左と呼ぶのか、人物の立場での左の目、画像のｘ座標の大きい側をさすのか？　そのチームではどういう定義を用いるのかチーム内での一貫性を重視すること。
　上限の扱い：範囲を指し示すときに、上限を含めるのか、上限を含めないのか？
　角度の向き：反時計周りを正とするのか、時計周りを正とするのか？　数学では、第１象限、第２象限、第３象限、第４象限の向きに（すなわち反時計周り）を用いることが多い。atan2(y,x)の返す角度の向きも反時計周りである。

 角度は、単位、正となる角度の向き、角度を0の開始の位置（12時の位置か、3時の位置か）によって、8通りの組み合わせを生じてしまいます。


#### **追記:必要十分な記述であることの重要性**
 ヘッダファイルが仕様書になるためには、「公開する必要のあるものだけをヘッダファイルに含めて、それ以外のものは含めてはならない」という鉄則を守る必要がある。
「前方宣言で十分なときには #include を使ってはいけません。」[Google C++スタイルガイド 日本語訳](http://www.textdrop.net/google-styleguide-ja/cppguide.xml)

また、 ヘッダファイルが仕様書になるためには、ヘッダファイルが十分に明快であることを要求する。多すぎてもいけないし、少なく過ぎてもいけない。必要でかつ十分な記述をする必要があるということである。実際のコードを書いていって、「あれ、これ足りないじゃない。」とか、余分な記述があって、「どっちが本当なんだよ」などとならないようにしなくてはならない。
　ソースコードを実装する人が読んで、必要なことが過不足なく書かれていることを満たしている必要がある。
だから、仕様書としての完成度が十分かどうかが、ばれやすいともいえるかもしれない。
　ある意味のあるまとまりが十分に明確であって、「これさえ理解していれば、あとは自由に使いこなせる」と感じさせる記述であることが望ましい。「それを使いこなすのは、全体を知らないと使いこなせないんだよね。」などともったいぶった状況にしないこと。「これさえ理解していれば、あとは自由に使いこなせる」ようにすることで、手離れのいいライブラリになることで、同僚が仕事を進めていってくれて、自分の作業が楽になる。

　必要十分な記述であれば、ある関数の動作が適切であるのかどうかの単体テストを記述するのに十分なだけ明確な記述になっているはずです。このヘッダファイルという仕様書は、単体テストをどう実装すべきかの仕様書にもなっているはずです。
　実装があやしいときに実装をすぐに修正するのではなく、まず仕様の明確化をはかり、単体テストを実装してエラーを見つけられるようにします。そして最後に実装を修正します。そのための基本となる書類がヘッダファイルです。ですから、何か疑わしいコードを見つけて、ヘッダファイルと実装のコードを同時に変更してコミットするのはよくありません。まずヘッダファイルだけ意味を明確にする修正だけをコミットします。
次にテストコードをコミットします。そして最後にバグの修正をコミットします。
　このような手順をふむことでヘッダファイルは仕様書としての役割をはたします。


付記：
ヘッダファイルを書く前に仕様書を書く必要がある場合（＝趣味の開発ではない場合）には、マークダウン言語で作成するようにし始めています。
１．外部仕様書を書く。
２．テスト仕様書を書く。
３．内部仕様書を書く。
　外部仕様書の中では、そのライブラリを呼び出す側が期待することを書き、そのような手法で実現するかを書かない。
　テスト仕様書は、その外部仕様にそった動作をライブラリがしているのかを確認するためにはどうしたらよいのかを記述します。
３．内部仕様書で初めて内部で使用するアルゴリズムや内部的なデータ構造が出てきます。
　
　従来の私の経験では、外部仕様と内部仕様とを区別しないために、使用するアルゴリズムを変更したとき、ソースコード上で変更の及ぶ箇所が多数にわたってしまうという問題を生じていました。それでは、多数の人員で開発する際に影響が及びすぎると気づいて、極力、外部仕様と内部仕様とを区別するようになってきました。オブジェクト指向の設計では、適度な隠蔽を設計に取り入れることができます。
　　

### markdown 記法の利用
ヘッダファイルを実装の仕様書にすることはできても、要件定義書をヘッダファイルで書くのは無理があります。
この場合　markdown記法で書くのがいいと思います。

[エクセルやワードの仕様書をマークダウン仕様書に変えよう](http://qiita.com/kitfactory/items/170c4ea17e8047ea0c95)
　
#### **追記**

[手離れのいい外部仕様を作成しよう](http://qiita.com/nonbiri15/items/9f58dd25a0a6efb91de6)を執筆しました。
　
[自作ライブラリでも画像データ構造を引数として画像処理の関数を実装しよう](http://qiita.com/nonbiri15/items/f1dc65eb520fc28d15b9)