設計文書のうまい書き方
プログラマは、日に日に多くの成果を少ない時間で上げられるようになっている。 今日の高級言語、開発環境、ツールや「RAD」の考え方によって、 プログラマもマネージャも極めて速い開発サイクルに順応しはじめている。 今やプログラマは一刻も速くコードを書こうと気持ちをはやらせている。
コードの前に設計をするプロセスは古びつつある。 設計を文書化するのは更に希だ。 多くの開発者は決して設計文書を書かない。文書なんて考えるだけでぞっとする。 命じられ仕方なく書くのは、大量のインタラクションの図やクラス図なんてのがありがち。 この図が設計時に開発者の考えたことを表していないことはよくある。 この記事では、どうやって効果的な設計文書をすっきりとまとめるか、その方法を議論する。 特別な道具はいらない。UML もいらない。 新しくプロジェクトを始める際、 良く書かれた設計文書がなぜ開発者にとって最も重要なツールになるのかも説明する。
設計文書は他人にものを伝えるのに使う。 設計上の判断(design decision)は何か、それはなぜ良い判断なのか。 UML に従っていなかったり、特別なモデリングツールを使わないからといって気に病むことはない。 設計文書の善し悪しを決める最大の要因は、 自分の意図をどれだけはっきり説明するかにあるからだ。
ただ、これには問題もある。 設計上の判断を伝えるには、読み手が誰なのかを考えないといけない。 同僚の開発者ならあるクラスの抽象化がよく練れていると理解するだろうが、 マネージャにはわからないだろう。 開発者とマネージャは設計の良さについて別の考え方をする。 必要な設計文書は二種類ある; 開発者向けとマネージャ向けだ。 それぞれには異る、しかし同じくらい大事な目的がある。 どちらもプロジェクトを始める時の役に立つ。
二つの文書は手に余ると思うかもしれないが、そんなことはない。 この記事では文書を再利用してうまくやる方法を紹介する。
良い設計はふつう、意味のある形で要求を満たしている。 設計のどの側面であっても正当化できないものは見直した方がいいかもしれない。 多くのプログラマが仕事にデザインパターンを持ち込みたがる。おかげで無駄にややこしくなる。 ある設計上の判断について、最低でも一つは要求からくる切実な理由があるべきだ。 で、その理由を文書化する。ある判断についてはっきりとした理由を挙げることができないなら、 その判断に価値は無いだろう。
図は設計を可視化する素晴しい道具だ。 しかし図では設計上の判断に潜む動機をあらわすことができない。 図の役割は設計文書の補助に留め、図自身を設計文書とすべきではないと念を押すのはこのためだ。
もう一つ大事なことがある。 設計文書には、設計上の判断から得られる利点を漏らさず書くこと。 そうすれば、他の人が読んだ時に、その判断から得られるものがわかる。 判断に伴うリスクについても書かなければいけない。 大抵の場合、他のプログラマは同じようなリスクに直面したことがある。 役に立つ指摘や、自分が考えもしなかった解決策を持っているかもしれない。 リスクを列挙しておけば、他の人もどんな潜在的リスクがありえるかを考えてくれるだろう。 チームの仲間はよく設計者が気付かなかった落とし穴に気付くもの。 図の中の四角形を並べ替える方が、コードを数百行書いてから前提が崩れたり、 コーディング中に予期せぬ罠にはまるより楽だ。 良い設計文書はコードを書く前から予期せぬ混迷に対処することができる。
更に文書は自分とマネージャやチームの中に共通の語彙をもたらし、 それを使ってプロジェクトの話をすることができる。 設計文書はマネージャにとって強力な道具になる。 普通なら専門的な技術力がないとわからないプロジェクトの中味を見せてくれるからだ。 利点を並べれば、マネージャはそこから設計の良さを感じとることができる。 開発の前にリスクを文書化しておけば、そのリスクをマネージャに引き渡すことができる。 リスクはマネージャが知っておくべきものだ。
最後に、設計文書は自分と、自分のマネージャやチームとの契約になる。 前提や判断やリスクを文書化し、他人に口をはさむ機会を与える。 「はい、まさに期待どおりです。」開発の舞台が進むにつれ、 設計文書は変更をプロジェクトの範囲に限るための基準(baseline)になる。 要求というのは変化するものだ。 しかし基準の文書があれば、 要求を誤解したせいで変更することは無いと主張する助力になる。
同僚向けに書く設計文書の目的は、 自分の考えは妥当か、他人の作業とあわせて動くかを確認する点にある。 開発者同士が計画を話し合わなければ、モジュールやクラスを繋ぐ時は確実に大惨事となる。 この手の文書を書く際の一般的なガイドラインを以下に示す。
この節では数パラグラフを費してそのプロジェクトやサブシステムが何をするのかを示そう。 解決しようとしている問題は何か? なぜそれが必要なのか? 誰が使うのか? こうした問いに答えて設計のスコープを決める。 書くのが難しいパラグラフがこの節にあるなら、 理解すべきドメインを理解できていないのだろう。 記述が数パラグラフに収まらないなら、スコープが大きすぎるかもしれない。 スコープが妥当かどうかを検証するツールとしてこの節を使おう。
高レベルなエンティティとはオブジェクトや、オブジェクトのグループなどのうち 設計での主たる構成要素となるもののこと。 良い例としては、データアクセス層、コントロールオブジェクト、 ビジネスオブジェクト一式などがある。
図 1 に例を示す。
この節ではそれぞれのエンティティが何をするものかを数センテンスで示そう。 記述は冗長でなくていい。個々のブロックの目的を説明すれば十分。 図の中で定義したブロックの根拠や目的を確認すること。
この節ではオブジェクトやオブジェクトの関係を定義する。 個々のオブジェクト(やオブジェクトの集合)について以下を定義する。
どうやってオブジェクトを使い、その機能が何なのかを一つのパラグラフに書こう。 オブジェクトが外部のオブジェクトやシステムと連携するなら、 そのオブジェクトのインターフェイスを示すのが良いだろう。 最も重要なのは、そのオブジェクトを定義するに至った思考プロセスを そこでもう一度書くことだ。利点とリスクを列挙しよう。 カプセル化をするなら、そのカプセル化が生む価値を書こう。 記述によって図に意味を与えよう。 冗長さは必要ない。ポイントを伝えられればいい。
オブジェクトに特別な設定や初期化が必要なら、 ここでそれを書いておくのは良いことだ。設定が必要ないならこの節はなくていい。
図 2 は図 1 で書いた System Security エンティティを補足する図の例だ。 完全な UML ではなく、UML のある面だけを使っている。 一番大事なのは、図が設計を示しているということだ。
モデルの完璧さは考えなくていい。 設計の骨組をぴったりと図にあらわすこと。 例では、2 つのセキュリティオブジェクトが 1 つの抽象オブジェクトから派生している。 そしてシステムのセキュリティモデルによって、ファクトリーがいずれかの適切な オブジェクトを生成してクライアントに渡している。
相互作用の図もこの節で書いておくと良い。 相互作用図 (訳注:interaction diagram, ここでは UML でいうシーケンス図を指す) は、複雑な処理をこなすため相互に通信するオブジェクトのエンティティ一式を示す。 図 3 はユーザーがログインするときの処理を示す図の例だ。図 1 に出てきたエンティティを幾つか使っている。
これも完全な UML ではないが、通信のシーケンスによって複雑な処理を行う様子は捉えている。 自分のシステムが他のサブシステムにあるオブジェクトと通信する際には こうした相互作用図が一番役に立つ。他の開発者はこの図を見て相互作用が正しいか検証する。
この節ではこの設計からくる最大の利点を 5,6 個と、 全ての 既知のリスクや懸念事項、そして全ての前提を列挙しよう。 部分的には前の節に書いた内容の焼き直しになるかもしれない。 重要なのは、そうした懸念を一箇所にまとめておくこと。 読者は文書全体を読まなくても利点やリスク、前提などを把握することができる。
この節からは何も削らないこと! リスクがリスクでなくなったら、その旨となぜリスクでなくなったのかをを文書化する。 決して文書から削除してはいけない。前提についても同じことがいえる。 この節を見ることで、現状の設計が持つリスクを簡単に把握できるようにしておくこと。
マネージャ向け設計文書の目的は、 そのマネージャがシステムの主なエンティティ、システムの利点、 あとなにより重要なのはリスクが何かを理解できるよう念を押すことにある。 自分は要求を理解しており、その要件を満たす方策がある。 文書はそれを示す機会とすることができる。
同僚の開発者向け文書を書いたなら、マネージャ向け文書を書くのは簡単だ。 その文書から 1, 2, 4 節を持ってくればできあがる。 文書を先のように構成しておけば、マネージャに不要な内容は一つの節に収まっている。 それは削ってしまえばいい。
設計文書を書く上で一番大変なのは、書くことではない。 難しいのはコードを書く前に論理的な設計をするところだ。 オブジェクトやエンティティを仕立て上げる見通しさえたてば、詳細を書くのは簡単。 あとはそれにワード・プロセッサや簡単なドローツールさえあればいい。 この作業でおこる一週間の遅れは、最後に信じられないほど報われるだろう。 こんな格言もある: 「計画に失敗するのは、失敗を計画するようなものだ ("If you fail to plan, then you plan to fail.")」