いものやま。

雑多な知識の寄せ集め

ソフト開発における「設計」とは何なのか。(その10)

前回は設計書に何を書いたらいいのかについて書いた。

今回は設計に関して少し補足をしたい。

アジャイル開発と設計の話

ここまででかなりじっくりと要件定義と設計の話をしてきているので、これはウォーターフォール開発向けの話だと思っている人も多そう。 あるいは「うちはアジャイル開発してるから設計なんてしないんだよね」なんていう人も。

まず、「アジャイル開発では設計をしない」というのはアジャイル開発に対する典型的な誤解。

次の図は『アジャイルサムライ』に出てくる図。

アジャイル開発でのプロセス

見ての通り、アジャイル開発でも分析(≒要件定義)や設計という工程は含んでいる。 なので、アジャイル開発だからといって要件定義や設計をしないというわけではない。

違うのは、前の工程が全部終わってから次の工程に行くというのではなく、段階的に何度も繰り返すというところ。 これはソフト開発における「設計」とは何なのか。(その4) - いものやま。で書いた図にも近い。 粒度の違いはあるかもしれないけど、繰り返し開発していき、その中で要件定義や設計していくというのは、ソフトウェア開発の基本的な考え方となっている。

ただし、設計はするけど、設計書を書くとは限らないというのは少し注意が必要。 これはソフト開発における「設計」とは何なのか。(その5) - いものやま。にも書いたけど、設計書はあくまでコミュニケーションのためのツールなので、別の手段でコミュニケーションが取れるなら、書かなくてもいいというのがあるから。

具体的には、アジャイル開発で使われることのあるプラクティスとして、ペアプロやモブプロというのがある。 これは担当者が一人で設計、実装していくのではなく、複数人でやっていくというもの。 みんなでワイワイと議論しながら作業を進めていくので、紙の上で方向性のコミュニケーションをする必要性が下がる。

あるいは、アジャイル開発だと同じ場所に集まって開発を進めた方がいいというプラクティスもあって、これも気軽にその場で相談や議論ができるので、方向性の確認が必要なら逐次その場でやっていけばいいというのがある。

あとは、とりあえず実装ができたら方向性がちょっと違っていてもOKとしてしまって、方向性の修正は次のイテレーションで行うという手もある。 繰り返しが短い期間で行われるので、ちょっと方向性が違った実装が出てきてしまっても、そこで学んだことを次の繰り返しで反映するのがやりやすい。 もちろん、開発に必要な工数自体は増えてしまうんだけど、間違った方向に進んだままリリースしてしまうというリスクをかなり抑えられる。

実際、ウォーターフォール開発で設計をしっかりと考えてみたけどコードを書き進めてみたら思ったよりも感触が悪いというのもよくある話。 そのときは、よく練られた設計を考えるよりもとりあえずの設計で動く実装を用意してみて、そこからのフィードバックを踏まえていい設計を考えて実装を直す方がよかったりする。

実現可能性との付き合い方

上記のアジャイル開発の方法と関連して、実現可能性の問題というのは常にある。

何かというと、設計を考えてみたけど、実際にやってみたらうまいこと動かなかったみたいな問題。 設計をするときはこれとどう付き合っていくかというのを考えておかないといけない。

一つの対策は、上記の通りアジャイル開発的な方法を使うというもの。 つまり、まずは動くものを作っておいて、繰り返しの中で必要に応じて改善していく。 こうしておけばとりあえず動くものがあるので企画倒れで終わることはないし、最悪そのままリリースもできる。

他の対策は、アジャイル開発の方法に近いんだけど、実際に手元で仮の実装を作って実現可能性を確認しておくという方法。 手元で試行錯誤した結果を踏まえて「この方法だとこういうメリットがある」「この方法だと問題があるからやらない」というのを書けると、設計書に説得力を持たせられる。

ただ、気をつけないといけないのは、手元で試した実装をそのまま「できました」と出しちゃうのはダメということ。 あくまで実現可能性を確認するためのコードなので品質に問題があるし、方向性が違って「なんじゃこりゃ」となったり、あるいは「じゃあそれで」と仮の実装なのにそのまま使われてあとで苦労することになりがち。 なので、方向性の確認は設計書でちゃんとやった方がいい。


一応これで設計のプロセスに関する話は終わり。

あとは実際にソフトウェアの設計をどう考えて作るといいかについて少し書きたい。

今日はここまで!

ソフト開発における「設計」とは何なのか。(その9)

前回はユースケース記述について書いた。

今回は設計書に書いた方がいいことについて。

設計書に書くといいこと

実際のところ、設計書に何を書いたらいいのかを画一的に述べるのは、かなり難しい。 というのも、ソフト開発における「設計」とは何なのか。(その5) - いものやま。にも書いたとおり、設計書というのはコミュニケーションのためのツールにすぎないので、十分なコミュニケーションを取れるかどうかで書く内容や量も変わってきてしまうから。 あるチームだと本当に簡潔な内容で済むかもしれないし、別のチームだと綿密に書く必要があるかもしれない。 開発の領域によっても書くべき内容は変わってくるしね。

ただ、とはいっても原則的なところはあるので、その原則を抑えたうえでチーム内でテーラリングしていけるといいんじゃないかと思う。

  • 概要から始め詳細へ分解する
  • 境界に注目する
  • 検討内容と選択理由を書く
  • ファイル一覧を書く
  • 影響範囲を書く
  • テスト設計する

概要から始め詳細へ分解する

設計書の大きな目的は、やろうとしている変更の方向性がちゃんとあってるかを確認すること。 なので、大きな方向性がまず間違ってないかを確認し、それをさらに小さく分解して、それぞれの方向性が間違ってないかを確認していくといい。

たとえば、まずシステム全体の構成を考えて、各モジュールの役割を考えて、その中でどういったクラスを用意するかを考えて、さらにはデータ構造はどうするのか、メソッドはどうするのか、どんなアルゴリズムを使うのかと、詳細へと落とし込んでいく。

もちろんこれは、開発の段階や内容、そして開発するエンジニアのレベル感によって、どこを書くのか、どこまで書くのかは変わってくる。

たとえば、一番最初の開発ならシステム全体のアーキテクチャから考え始めないといけないわけだけど、その後の開発なら全体像はもう決まっているので、今回開発する部分にだけ絞って記述すればいいとなる。 あるいは、ライブラリ開発だとシステム全体のことは気にしないでライブラリ内の構成だけ考えればいいし、逆にマイクロサービスを組み合わせて大きなサービスを作り上げるとかだと全体の構成や他のサービスへの影響とかも考える必要が出てくる。 あと、シニアなエンジニアなら設計では概要レベルだけ書いておけばあとはお任せでOKとなるけど、ジュニアなエンジニアに任せる場合は設計段階でより詳細まで詰めておいた方が安心できる。

このあたりの調整は必要。

で、その調整をしやすくする意味でも、設計書も何回かに分けて途中で確認しながら書いていくといいところはある。

まずは書こうと思っていることの目次だけ用意してチェック。 次に概要レベルの部分を書いてチェック。 それもOKならそれより少し詳細に入ったところまで書いてチェック。 みたいのを繰り返しながら、もうあとは大丈夫かなというところで設計書は完成にして、その方針にしたがって実装するみたいな。

境界に注目する

上記とも少し関係するところだけど、システムというのは完全な一枚岩でできているわけではなく、いくつかの部品が組み合わさってできあがっている。 で、部品内の作りはいくらでも変えられるんだけど、部品と部品をつなぐ部分、つまり境界については、簡単に変えることができない。 なぜなら、そこを変えると両方の部品に変更が入ってしまうから。 なので、部品と部品の境界、すなわちインタフェースについては、しっかりと考えた方がいい。

なので、まずシステムのどこに境界があるのかをちゃんと把握するといい。 そして、その境界のインタフェースをしっかりと定める。

さらにいうと、部品は普通入れ子構造になっていて、部品の中にはさらに小さな部品が集まっていたりするはず。 なので、必要なところまでブレークダウンしていく必要がある。

たとえば、フロントエンドとバックエンドが協調して動くなら、まずそこに境界があり、インタフェースが存在することになる。 これは普通はWebAPIとして規定されるはず。 さらにはバックエンドの中にも複数の層があったりして、そうなるとその間にも境界があり、やはりインタフェースを規定することになる。 その各層にも複数のモジュールが含まれていたり、さらには複数のクラスがあったり、みたいな。

これもどこまで掘っていくかというのはあるんだけど、そうやって境界を意識することで、かっちりと決めておかないといけない部分が見えてくると思う。

検討内容と選択理由を書く

設計というのは「How」すなわち「どうやるのか」の取捨選択だということを書いた。 なので、要件定義書と同じように、「なんでその選択をしたのか」というのを書いておくといい。

とくに「この方法ではやらない」というのを書いておくといい。 理由についてはこれも要件定義書と同じで、選ばれなかった方法についてはソースコードに何も情報が残らないから。

ファイル一覧を書く

そんな感じで検討しながら詳細に詰めていくわけだけど、ついでにこれを書いておくといいかなというのがファイル一覧。 今回の開発で、このファイルが新規に増える、このファイルに変更が入る、このファイルは削除する、というのをツリーで書いておくイメージ。

- project_dir/
  - hoge/
    - hoge.py  # 新規;XXクラスを実装
    - huga.py  # 変更;XXクラスに対応、piyo.pyと統合
  - (piyo.py)  # 削除 -> huga.pyへ統合
  - ...

みたいな。

これを書いておくと以下のようないいことがある:

  • どのあたりに変更が入るか分かりやすい
    • 変更する場所や内容が適切かがこれでけっこう分かる
  • 新規ファイルの場所や名前を適切にしやすい
    • バージョン管理でファイルの位置や名前が変わると変更を追跡しづらくなるので、作ってしまってから変えるのではなく、あらかじめ合意をとっておいた方がいい
  • 変更の影響が分かりやすい
    • 意外なところにも変更が入ると気づけると、影響範囲の推測でミスしづらくなる

ちなみに、ファイル全部を書くのは大変なので、今回の開発に注目したところだけ書くのでOK。 書く量が多すぎるならディレクトリレベルで「このディレクトリ以下に変更が入る」とかでもいい。 まぁ、書く量が多すぎるとしたら、ちょっと設計として問題ありなのかもみたいな嗅覚も働かせたいところだけど。

影響範囲を書く

開発で怖いのはデグレ。 なので、今回の変更でどこら辺のコードにも影響が発生するのかは書いておいた方がいい。 これを複数人でレビューしておくことで、影響範囲の考慮漏れがないかとかを考えられる。

このときに注意したいのは、影響を受けるのはコードだけじゃなくて、ドキュメントやテストもあるということ。 今回の開発によって新たにドキュメントを作る必要が出てくるとか、ドキュメントのここの記載が変わってくるとか、今まで通ってたこのテストが通らなくなるとか。

そのあたりを抑えられてないと、あとになってドキュメントの記載が間違ってるという話がきたり、テストが急に通らなくなったんだけどとかが出やすい。

ちなみに、ドキュメントやテストのソースもあるなら、上記のファイル一覧を書くときにそれらに対しても「このファイルに変更が入る」と書いておくことになる。 そういった意味でもファイル一覧を書いておくのは影響範囲の考慮漏れを防ぐのによかったり。

テスト設計する

あとはテスト設計も書いておくと安心なところがある。 もちろん、厳密に書くと大変なので、基本的には「こんな感じのテストをしようと考えてる」くらいでOKだけど。

ただ、データの境界値とかが明確に決まっているのなら、その仕様についても書いておくといいかも。 あとでテストレビューをするときに、境界値に対してちゃんとチェックできてるかが確認しやすいので。


以上が抑えられていれば、コードが出来上がってきてから「思ってたのと違った」となるリスクをだいぶ抑えられると思う。 かつ、設計書自体のボリュームもそれなりに抑えられるかなと。

今日はここまで!

ソフト開発における「設計」とは何なのか。(その8)

前回は要件定義のやり方について書いた。

今回はそれに付け加える感じで、ユースケース記述の話。

ユースケース記述

ユースケース記述というのは、システムがどのように使われるのかという一連の流れを書いたもの。

一例を挙げると、たとえば「ユーザがログインする」という場合なら、

  1. ユーザがブラウザで特定のURLにアクセスする。
  2. システムはログイン画面を表示し、ユーザにメールアドレスとパスワードの入力を求める。
  3. ユーザはメールアドレスとパスワードを入力し、「ログイン」ボタンを押す。
  4. システムは入力されたメールアドレスとパスワードで認証を行い、認証ができたらユーザのマイページを表示する。

みたいな。

このユースケース記述というのはシステムを外部から見たときの振る舞いを規定するものなので、要件定義というよりかは基本設計で考えるものではあるんだけど、できれば要件定義の中で追加でやっておいた方がいいと思っている。 なんでかというと、このユースケース記述をお客さんに共有することで、実際に自分がそのシステムを使うときの様子をイメージしてもらうことができるから。 この段階で「思ってたのと違う」というのが分かれば、システムを作り出す前に方向性の修正ができる。

このユースケース記述はシステムの内部の動きについては細かく書かないので、お客さんも理解できるギリギリのところにある設計となっている。 なので、ユースケース記述を共通言語してシステムの振る舞いを積極的に議論しておくといい。

ちなみに、このユースケース記述をちゃんと作れるかどうかが設計の肝なところがある。 というのは、近頃ドメイン駆動設計(DDD)が声高に叫ばれてたりするけど、このユースケース記述の中に出てくる用語や概念、その適切な値、振る舞いといったものが、まさにドメイン知識だから。

ドメイン駆動設計をやろうとして、でも何がドメイン知識なのか分からないみたいな話を聞くことがあるけど、それはドメイン知識を抽出する方法を知らないからだと思っている。 ドメイン知識というのはユースケース記述から抽出するものなんよね。 そして、ユースケース記述から抽出するからこそ、お客さんとの共通言語としての機能を果たせるというのがある。 オブジェクト指向分析設計でこのあたりの知識は語られてるはずなんだけど、なんか抜け落ちてしまっているせいで、テクニックに走りすぎて実際のドメイン知識はスカスカの軽量DDD(というか形骸DDD)が生まれてしまってると思うんだよなぁ・・・オブジェクト指向分析設計がちゃんと復権してくれるといいんだけど。

ユースケース記述のポイント

さて、ユースケース記述を書く上で、いくつか気をつけたいことを書いておきたい。

まずは、個々のユースケース記述をやっていく前に、ユースケースの一覧を用意しておくこと。 一覧で見れるようにしておくことで、ユースケースに抜け漏れがないかを確認しやすくなる。

一つ注意したいのは、このユースケース一覧というのは、システム全体のユースケースじゃなくて、今回の開発対象のユースケースということ。 全部のユースケースを書いてたら、いくら時間があっても足りないので。

そして、ここのユースケース記述をするときに気をつけたいのは、「主語」。 ここでもやっぱり主語が重要。 日本語だとついつい省略しちゃいがちなんだけど、「誰が」何をやるのかをハッキリさせておかないと、あとで「あれ?」ってなることが出てきやすい。

たとえば「毎日9時に在庫情報に矛盾がないか確認する」みたいな記述があると、誰がこの確認をするのかがハッキリしない。 決まった時間という意味ではシステムがやりそうな感じがあるけど、9時という時間だと管理者がやる可能性もワンチャンありそうな。 ましてやこのあとに「在庫情報に矛盾があった場合、修正を行う」みたいな記述が続いてたら、管理者が確認してシステムに修正情報を打ち込むのか、システムが確認して修正できるところを自動で行うのか、みたいになってくる。 いずれにせよ、解釈に揺れが生じて、「思ってたのと違った」となる危険性が高い。

あと、主語を書くときに、ユーザ側については「ロール(役割)」も意識した方がいい。 同じシステムであっても、管理者ができることと一般ユーザができることというのは違ったりする。 なので、単に「ユーザは顧客情報を入力する」「ユーザは使用明細を見る」のように書くのではなく、「管理者は顧客情報を入力する」「一般ユーザは自分の使用明細を見る」のように、どのロールで振る舞った場合のユースケースなのかが分かるような主語になっているといい。

他には、システムがバッチで動くとかなら「いつ」動くのかとかもちゃんと書いておきたいかな。 まぁそんな感じで、システムの外側から見た振る舞いに関して、できるだけ曖昧なところが生じないように書いて合意をとっておけるといい。

一方で、ついやってしまいがちなのが、システム内部の処理を細かく書きすぎてしまうこと。 この条件ではこう計算してとか、ループをどう回してだとか。 ユースケース記述を書くのって、フローチャートを書いてるのに近い感じはあるからね。

ただ、そういった内部の動きはお客さんも言われても困るだけから、書いてもしょうがない。 なので、システム内部の細かい動きには触れず、ユーザとシステムのちょうど境界の部分について書けるといい。

要件定義書に書くといいこと

ということで、要件定義書に書いておくといいことは、以下のような感じ:

  • 開発の目的
    • 顧客が何を望んでいるか
      • 深掘りして、要件に繋げられるレベルにしておく
    • リファクタリングなら、開発者が何を望んでいるのか)
  • 要件定義
    • 要求を満たすために、開発者は何を行うのか
      • 〜〜機能を新しく作る
      • 〜〜機能を修正する
      • (〜〜機能を廃止する)
      • (開発後にシステムが満たしているべき条件(非機能要件))
    • 検討したけど実施しないことは何か、どうして実施しないのか
  • ユースケース

このレベルでお客さんと合意が取れていると「思ってたのと違った」というのが起こりにくいし、開発者側もドメイン知識の抽出やシステムの作りをイメージしやすくなる。

今日はここまで!

ソフト開発における「設計」とは何なのか。(その7)

前回は、要求と要件の違いは「主語」で、それぞれを考えるときには視点を切り替える必要があることを書いた。

今回はそれを踏まえて要件定義のやり方を書いてみたい。

要求の深掘り

開発はお客さんから「〜〜がしたい」とか「〜〜機能がほしい」とか言われてスタートすることが多いと思う。 ただ、このときそのまま「〜〜できるようにする」とか「〜〜機能を追加する」のように要件にしてしまうのは避けた方がいい。

これにはいくつか理由がある。

まず、本当にほしいものとズレている可能性があるということ。 「顧客が本当に必要だったもの」の風刺画にあるように、本当に必要なものをちゃんと分析して自分で規定することはとても難しい。 もちろん、それはお客さんではなくこちらで考えても難しいことなんだけど。 ただ、お客さんと会話して深掘りしたりモックを見せたりすることで、「思ってたのと違った」というのを早めに潰しておけるならそれに越したことはない。

そして、要求は深掘りしてより深い要求として理解した方が、その要求を満たせる手段の幅も広がるというのがある。 「ドリルの穴理論」の話にあるように、「ドリルがほしい」というレベルの要求の理解だと、それを満たす手段は「ドリルを売る」としかならない。 けど、「なんでドリルがほしいんだろう?」というのを深掘りして「壁に穴を空けたい」という要求が分かれば、「ドリルを売る」以外にも「ドリルを貸し出す」「人を派遣して穴を空ける」などの手段も考えられる。 さらに深掘りして「どうして壁に穴を空けたいんだろう?」というのを聞いてみたら「壁に絵画を飾りたいから」という要求が分かったりするかもしれない。 もうそうなると本当に必要だったのは壁の穴ですらない可能性も出てくる。

あと割とあるのが、単なる思いつきだったという話。 そういった思いつきをそのまま作って提供すると、作ったけど結局使われないままということがよくある。 それでもお金がもらえるならいいんじゃない?という意見もありそうだけど、実は落とし穴がある。 それは作った機能は使われてなくてもメンテし続けないといけないということ。 そうやって使われないゴミ機能が増えてしまうと、他の機能を追加するときの足枷になるし、やる価値のないバグ修正やテストで工数が膨れ上がることになる。

そんな感じで、要求の深掘りは重要。

そして、要求の深掘りをするときに重要なのが、顧客視点になるということ。 要求は主語が「顧客」なので、自分が開発者であることは一旦忘れて、顧客の立場になって、どうして〜〜したいのか、〜〜機能がほしいのかということを深掘っていく。

このとき、とくに意識したいのが「顧客が困っていること」。 困っていることを解消するのはすごく価値が高いというのがまずあるし、困ってることは明確なのでそれを解消するのは要求としてズレにくいというのもある。

逆に「あれば嬉しいこと」は難しくて、実際に作ってみても意外と使われないことも多い。 なくても別に困らない機能って、よほどの嬉しさがないと使わないんよね。

要件の検討

こうして顧客の要求を分析したら、それを満たすための要件を検討する。

ここからは顧客視点で考えていたのを一転させ、開発者視点で考えていくことになる。 顧客の要求を満たせるような手段を開発者として考えて、妥当な点を見つけていく。

この妥当な点というのは、「やりたいこと」と「できること」の均衡点。

「やりたいこと」は顧客が要求するもので、顧客視点では当然最大限満たされることが望ましい。 けど、開発ではそれを完全に満たすことは難しい。 技術的に実現可能かどうかがまずあるし、可能だとしてもコストがとてもかかってしまって現実的ではない場合もある。 なので開発者視点では「できること」に限りが出てくる。 そこで、「やりたいこと」ーー上(顧客)からの力学と、「できること」ーー下(開発者)からの力学とで綱引きが発生して、コストや納期なども踏まえてその綱引きが均衡する点が要件として定義されることになる。

そんな感じで「開発者が」やること、満たすべき条件を要件としてまとめる。 これはその開発でのスコープになる。

気をつけたいのは、これはソフトウェアの要件ではなく、開発の要件ということ。 すなわち、開発で作るソフトウェアの差分についての要件を書くことになる。 なので、「新規に〜〜機能を作る」「従来機能を〜〜に変更する」(場合によっては「〜〜機能を廃止する」)といったもののが要件となる。

ちなみに、ここでは主に機能要件を挙げてるけど、他にも性能やリソースなどの非機能要件もあるので、それらも必要に応じて定義することになる。

「やらないこと」の記録の重要性

あと、要件定義では「やること」だけではなく、「やらないこと」とその理由も実は書いておいた方がいい。

これは、「やること」は実際に開発が進むので明確に残るのに対し、「やらないこと」は開発が行われないので、文書に残しておかないとそもそも検討のテーブルに上がってたのかどうかすら分からなくなってしまうから。

あとになって「現状こうしてるけど、なんでこうしなかったんだろう?」みたいな疑問が浮かぶことはよくあるんだけど、やらなかった理由が文書として残っていれば、その疑問をすぐに解消できる。 そもそも検討のテーブルに上がってなかった(開発当時よりあとに出てきた手法とかだとよくある)のであれば、その方法を新しく検討してみる価値はあるだろうし、検討のテーブルに上がってはいたけど明確な理由があって採用されなかったというのであれば、それを知らずに再検討してやっぱり使えないとなる無駄を避けることができる。 あるいは、上記の力学の都合で採用されなかったり改善が先延ばしになっている場合もあるので、それであれば優先度に応じてその方法に切り替える開発を行うことも考えられる。

そんな感じで、どうしてやらなかったのかの理由はちゃんと書いておいた方がいい。

今日はここまで!

ソフト開発における「設計」とは何なのか。(その6)

前回は以下のようなことを書いた:

  • 開発は「Why(要求)→What(要件)→How(設計)」の順にブレークダウンしていく必要がある
  • ブレークダウンでは複数の選択肢が考えられるので取捨選択が必要
  • 選択した方針が間違ってないかのコミュニケーションが必要で、そのために要件定義書や設計書を書くといい
  • コミュニケーションが不要なら文書はなくてもいい(ただし要件定義や設計自体は必要)

今回は、要件定義を考えていくために、要求と要件について深く考えてみる。

要求と要件の違い

要件定義について考える前に、そもそもの話として「要求」と「要件」の違いが何なのかをハッキリさせておいた方がいい。 「要求と要件の違いって何?」ってあらためて聞かれると、ちゃんと答えられない人は多いと思う。

かく言う自分も、昔はこの違いでかなり悩んだ。 というのも、会社で用意されていた要件定義書のテンプレートで、要求を書く章と要件を書く章が分かれてたから。 要求も要件も同じじゃね?ってなってると、それぞれに何を書いたらいいのか分からないとなる。

要求と要件の違い、それは何かというと、「主語」が違う。

要求の主語は基本的に「顧客」となる。 「顧客は〜〜したい」「顧客は〜〜がほしい」のように、「顧客が」望んでいることが要求であり、その要求を満たすために開発は行われる。

一方で、要件の主語は常に「開発者」となる。 要求を満たすために「開発者は〜〜する」のように、「開発者が」やること(および守るべき条件)が要件となる。

ここで少し補足しておくと、要求の主語は「顧客」以外の場合もある。 たとえば「リファクタリングしたい」とか「ログを出せるようにしたい」とかは顧客ではなく開発者の要求なので。 もちろん、そのさらに奥には「顧客は新規機能の開発速度を上げてほしい」「顧客はバグを踏みたくない」「顧客は問題が起きたときに早く修正が入ってほしい」などの顧客の要求があるわけだけど。

それに対して、要件の主語は常に「開発者」であることに気をつけたい。 要求が何であれ、それを満たすために手を動かすのは「開発者」以外にありえないから。

いずれにせよ、「主語」を意識することがすごく重要。 そしてそれは、要求を考えるときと要件を考えるときでは、視点を変える必要があるということにも繋がる。

その話はまた次にしたい。

今日はここまで!

ソフト開発における「設計」とは何なのか。(その5)

前回は、開発とはソースコードの差分を作ることであり、設計書とはその差分をどう作るか説明する文書であることを書いた。

そのうえで、設計書が本当に必要なのかどうかを考えていきたい。

設計書は必要か?

そもそも「設計書は必要なのか?」という疑問がなぜ生まれてくるのかというと、設計書がなくてもコードは書けるから。 開発で生み出すのが「ソースコードそのもの」であろうが「ソースコードの差分」であろうが、これは変わらない。

で、ぶっちゃけた話、個人開発の場合は設計書を書く必要性はあまりない。 そして、チームでの開発だとしても、実装前に方向性の確認がとれてそれを記録に残せているのであれば、設計書はなくてもいい。

これはなぜかというと、結局のところ文書というのはコミュニケーションの手段にすぎないから。 個人開発の場合はコミュニケーションをとる相手もいないので不要だし、チーム開発だとしても設計書で行うべきコミュニケーションが別の手段でできているのなら不要となる。 設計書という形式にこだわる必要はない。

ただ、その場合も「設計」自体は必要なことに気をつける必要がある。 そして、チームで開発する場合も「別の手段でできているなら」という条件がちゃんと満たされることは滅多にないので、基本的にはちゃんと設計書を書いた方がいい。 じゃないと、結局のところ「設計」がちゃんとされないままにコードが書かれて、コードレビューをしようとなった段階で「なんじゃこりゃ」みたいに発覚、その時点ではもうどうしょうもなくなってるということが起きがちなので。

そもそも「設計」とは何なのか?

ただ、上のように書くと、「そもそも『設計』って何なんだ?」ってなりそう。

  • 「設計書」は不要な場合もあるけど、それでも「設計」自体は必要とは、どういうことなのか?
  • ちゃんとした「設計」がされてないとは、どういうことなのか?

これを理解するには、「Why-What-How」の構造を意識する必要がある。

開発とはソースコードの差分を生み出すことだけど、それを実施するのは何かしらの理由があるからだ。 たとえば新機能がほしいだとか、バグを直す必要があるからだとか、将来の拡張のためにコードを整理する必要があるからだとか。 まぁいろんな理由があるにしろ、理由もないのにソースコードをいじることはありえない。

なので、開発のスタートにはまず「Why」つまり「要求」がある。

その要求を受けて、じゃあ実際に何をやっていくのか(あるいはやらないのか)を決める必要がある。 そうして決まるのが「What」であり、「開発で実現すること」すなわち「要件」となる。

要件が決まったら、今度はそれを実現するための方法を考える必要がある。 そうして得られるのが「How」で、「要件を満たすための方法」すなわち「設計」となる。

  • Why:なぜ開発するのか(要求)
  • What:何を開発するのか(要件)
  • How:どう開発するのか(設計)

これをちゃんとWhy-What-Howの順にブレークダウンしていかないと、「何やってるの?」な開発になってしまう。 たとえば「東京から大阪に行きたいんだけど?」と言われてるのに「名古屋行きの切符を買うことにしましょう」と提案するのは変だし、ましてや「車を借りて横浜まで行きました」と報告されたらもう意味不明なわけだけど、実際の開発だとそういうことが起きがち。

そして重要なのが、1つのWhyを満たすようなWhatはたくさんあるし、1つのWhatを満たすようなHowもたくさんあるということ。 つまり、取捨選択の必要がある。 そして、たくさんあるWhatの中で実施するWhatを決める(と同時に実施しないWhatを決める)のが「要件定義」であり、たくさんあるHowの中で実行するHowを決める(と同時に実施しないHowを決める)のが「設計」となる。

そういった取捨選択をやらず、お客さんに言われたままのことをやったり、とりあえずでパッとコードを変更してしまうと、あとになって方針が全然間違ってることが分かって大きな手戻りが発生する可能性が出てくる。 というか、手戻りできるならまだよくて、大抵はスケジュールに追われて「現状が仕様」のゴリ押しになることが多い。 そうなると、あっという間にゴミだまりのソフトウェア、ソースコードの出来上がりとなる。。。

そういったことが起きないようにするためには、ちゃんと取捨選択ーーすなわち「要件定義」や「設計」ーーを行い、それが間違った方針になってないかをコミュニケーションしていく必要がある。 そのための文書が「要件定義書」や「設計書」となる。

今日はここまで!

ソフト開発における「設計」とは何なのか。(その4)

前回は「ソースコードを説明する文書」は「設計書」ではなく「開発者向けドキュメント」にすぎないという話をした。

では、結局「設計書」とは何なのかというのが今回のお話。

ソフトウェア開発の特異性

ソフトウェア開発では、製造業での開発と全然違う点が1つある。

それは開発がワンショットで終わらないということ。

製造業では一度設計書まで作ったら、あとはそれを製造するだけとなる。 基本的に設計書は使い切りで、細かい修正を入れたり、別の開発で参考にすることはあっても、その設計書にさらに手を加えて新しい設計書にするというのは考えられない。 企画した開発ごとに新しい設計書を書いていくことになる。

これがソフトウェア開発だと違ってくる。

一度ソースコード(=プログラムの設計書)を書いてプログラムをリリースしたあとも、次なる開発では基本的にはそのソースコードに手を入れて新しいプログラムをリリースしていく。 ソースコードは1回書いたら終わりというわけではなく、ずっと使い回しで更新されていく。 もちろん、どこかで従来のコードを捨てて1から新しく書き直すということもあるけどw

これは「製品」という枠で考えたときに、製造業では開発が1回で終わるのに対し、ソフトウェア開発では開発が複数に分割されているとも言える:

製造業の場合

製品 開発 設計 製造
製品A
製品A開発 製品A設計書 製品A
製品B
製品B開発 製品B設計書 製品B

ソフトウェア開発の場合

製品 開発 設計 製造
製品A
製品A ver.1開発 製品Aソース ver.1 ※新規 製品A ver.1
製品A ver.2開発 製品Aソース ver.2 ※更新 製品A ver.2
... ...(更新が続く) ...
製品B
製品B ver.1開発 製品Bソース ver.1 ※新規 製品B ver.1
製品B ver.2開発 製品Bソース ver.2 ※更新 製品B ver.2
... ...(更新が続く) ...

なので、ソフトウェア開発で作っているものは、実は「ソースコード」ではなく「ソースコードの差分」だったりする (ちなみにこれはver.1の開発のときも同じことが言える;「ソースコードの差分」=「ソースコード」となっているだけ)。 ソースコードを作ってるんだと勘違いしやすいけど。

そこに気付けばソフトウェア開発における「設計書」が「何の」設計書なのか分かるかと思う。

そう、ソフトウェア開発における「設計書」というのは、開発で生み出す「ソースコードの差分」を設計、説明した文書となっている。

ソースコードそのもの」ではなく「差分」を説明しているのが肝。 「そのもの」の説明だとソースコードの変化に追従していかないと腐るわけだけど、「差分」であればそれは変化していくものじゃなくて変化の内容それ自体なので、腐ることがない。

ちなみに、「要件定義書」というのも同様で、今回の開発(=生み出すソースコードの差分)で何を実現するのかを規定している文書といえる。 「ソースコードそのもの」で何を実現するかとなっちゃうと、対象の開発とは関係ない要件や仕様までカバーする必要が出てきちゃうからね。

図解すると次のようになる:

ソフトウェア開発の様子

ここまでを一度まとめておくと以下のようになる:

こうしたときに、それでもなお「設計書」は不要なのかや、必要なのだとしたらどういったことを書けばいいのかについては、次回以降に書きたい。

今回はここまで!