設計
新人プログラマ応援

はじめに

「設計してください」と言われて何をするか、分かるでしょうか。
明確に分かるという場合はよいと思います。成果物が決まりきっているなら幸運です。
しかし、例えば新しい技術・業務などにおいては、設計が何か漠然とすることがあります。
そういう、設計タスクそのものが曖昧な際に使えるようなことを書こうと思います。

ただし持論です。
設計についていくら調べても、出てくるのは具体的な何かに対するタスクのみでした。
もちろん私が見逃しているだけの可能性は大いにあります。

「設計とは?」を知る重要性

IT業界は進化が速いです。
そしてますます複雑になっていきます。常識が少しずつ変化していきます。
その度に「設計って何すれば良いんだ?」となるのは困ります。どんな領域であっても「設計する」を自信を持って行いたいです。

Wikipediaで確認

https://ja.wikipedia.org/wiki/%E8%A8%AD%E8%A8%88

設計(せっけい、英: design)とは、建築物や工業製品等といったシステムの具現化のため、必要とする機能を検討するなどの準備であり、その成果物としては仕様書や設計図・設計書等、場合によっては模型などを作ることもある。
時間的なものとしては、製作開始時期・供用開始時期・想定使用期間・量産品の場合の製作継続期間などがある。機能的なものとしては、使用目的・体積・面積・質量などがある。社会的な状況・環境としては、法的規制・地球環境などがある。試作は、仕様の検討のための手段であり、納得または合意するまで試作を繰り返す。使用できる資源の組み合わせは多くある。ライフサイクルコスト(生涯費用):調達可能な金額であるか。また、保守、廃棄を含めて、一番安く済む手法であるか。機械・器具・部品など:製作開始までに調達可能であるか。量産品の場合の製作継続期間中に途切れることなく調達可能であるか。保守:想定使用期間の間、保守に必要な部品・器具・作業員などが確保できるか。製造・試験・保守・廃棄作業を考えると、使用できる組み合わせが少ないことがある。

はーむずい

設計を英語にするとDesignです。
Google日本語翻訳しました。
https://en.wikipedia.org/wiki/Design#Definitions

より正式には次のように定義されています。
(名詞)制約に従って、一連の要件を満たすプリミティブコンポーネントのセットを使用して、特定の環境で目標を達成することを目的としたエージェントによって明示されたオブジェクトの仕様。 (設計者が動作する)環境で、設計を作成するための[動詞(推移的)] [3]
デザインのもう1つの定義は、「法的、政治的、社会的、環境的、安全性の中で、仕様、計画、パラメータ、コスト、活動、プロセス、および方法と行動を定義する、独自の期待を達成するためのロードマップまたは戦略的アプローチ」です。その目的を達成する上での経済的制約があります」。[4]
ここで、「仕様」は計画または完成品のいずれかとして明示することができ、「プリミティブ」は設計オブジェクトを構成する要素です。
そのような広い意味では、すべての分野のデザイナーのための普遍的な言語や統一機関は存在しません。これは、主題に対する多くの異なる哲学とアプローチを可能にする(下記の哲学とデザインの研究を参照)。
デザイナーと呼ばれるデザイナーとは、通常、ファッションデザイナー、コンセプトデザイナー、ウェブデザイナー、インテリアデザイナーなど、どのエリアが扱われているかを専門とするさまざまなデザイン分野の1つで専門的に働く人々のための用語です。 。設計者の一連の活動は設計プロセスと呼ばれ、設計の科学的研究は設計科学と呼ばれている[5] [6] [7] [8]
デザインの別の定義は、オブジェクト、システム、コンポーネントまたは構造を製造することを計画することです。したがって、「デザイン」という言葉は、名詞または動詞として使用できます。より広い意味では、設計は技術と統合された応用芸術と工学である。

ソフトウェア設計
https://ja.wikipedia.org/wiki/%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2%E8%A8%AD%E8%A8%88

考慮すべき点[編集]
ソフトウェア設計にあたっては、様々な観点を考慮する必要がある。ソフトウェアが達成しようとしている目標を反映しているため、それらは重要である。そのような観点の一部を以下に挙げる。
拡張性 - 基盤となるアーキテクチャに大きな変更を加えることなく、新たな機能を追加できること。
頑健性 - 高負荷状態や不正な入力があっても動作すること。例えば、使用可能なメモリ量が少なくても動作するよう設計する。
信頼性 - ある一定期間まで、特定の困難な状態になっても、機能すること。
耐障害性 - コンポーネントの障害が発生しても、それに耐えたり、回復させたりできること。
セキュリティ - 悪意ある行為に対して耐性があること。
保守性 - ある一定時間で、特定の状態に復帰できること。例えば、アンチウイルスソフトのように、定期的な更新が可能であるなど。
互換性 - 他の製品と相互にやりとりできること。あるいは、過去の代替すべき製品と互換であること。
モジュール性 - モジュール性を考慮した設計。それによって保守性も向上する。開発においてもコンポーネント単位で実装し>テスト可能などの利点がある。また、開発作業の分割が容易になる。
再利用 - モジュール性がよければ、個々のコンポーネントを他の場面で再利用できる可能性が生じる。

わかりました。1年ください。

設計とは

設計そのものは、誰しもぼやーっと理解しているのではないでしょうか。
ただそれそのものを理解しようとすると大変なので、なぜ設計する必要があるかからアプローチしていきます。

nazo1.jpg

「設計する」理由から逆算する

設計しないとどうなるんでしょうか。適当に作り始めたらダメなんでしょうか。
よくYAGNI原則と言ったりするじゃないですか。
You Aren’t Gonna Need It. 必要になった時に考えろ! です。

もちろん、上手く行かないことが経験的にわかると思います。
気づいたときには後戻りできない、またはしづらいケースがあります。
その為に予めよくよく考えておかなければなりません。
それこそ設計の本質だと思います。

困らないように「あらかじめ設計する」

ソフトウェアで考えると少し分かりづらいですが。
例えば板から机を作ろうと言う時に、設計図がないと板を切った後に戻せなくなってしまいます。

そのような困るケース、つまり「上手くいかないケース」というのがあります。
タイプを挙げるとおそらくこんな感じでしょう。

  • 元に戻せない
  • 完成しない(詰む)
  • 目標を達成できない
  • 矛盾が生じる
  • 進まなくなる

例を挙げると

  • 物を加工する前に、加工方法について考える
  • 今後の行動を考える(計画)
  • 意図したとおりに動くように、クラスを配置する
  • 皆の認識を合わせる

これらの中には別の名前がついているものもあります。
特に時間が絡むものは「計画」と言ったりします。

補足:計画は設計なのか?

計画は設計の一部でしょうか?
Wikipediaの「設計」に照らし合わせると違う気がしますが、「Design」に照らし合わせるとそう言えるかもしれません。
一旦深く考えないことにしましょう。

設計のもう一つの側面

「困らないように予め行うこと」を設計と言ってしまうと、準備が全て設計になってしまいます。
しかしそうではないはずです。具体的な製造ではなく、頭で考える部分と、骨組みの部分を設計と呼ぶのが直感的にあっているのではないでしょうか。

sekkei.jpg

すると、自ずとタスクとしてはパターン化してくると思います。

  • 動くように計算する
  • 取捨選択する
  • 依存関係をコントロールする
  • 効果的に配置する など

こちらの方が一般的に言われる設計のイメージだと思います。
小難しいように思えますが、これはまさにプログラミングそのものに近いです。

シンプルな定義(仮の)

設計とは一言で言えば
後で困らないために、取捨選択したり、効果的に配置したり、依存関係をコントロールしたり、動くように計算したりすること。

こんな感じでどうでしょう?
以下、これを前提に話を進めます。

ソフトウェア設計を簡単に理解する

ソフトウェア設計の説明が難しいのは、今のプロジェクトにこの設計が必要かどうか分からないからだと思います。
それは「困る場合」で考えてしまえば良いわけです。

項目 説明 設計が必要か?
拡張性 基盤となるアーキテクチャに大きな変更を加えることなく、新たな機能を追加できること。 新たな機能を追加する時に困る場合
頑健性 高負荷状態や不正な入力があっても動作すること。 高負荷状態になると困る場合。不正な入力があると困る場合
信頼性 ある一定期間まで、特定の困難な状態になっても、機能すること。 ある一定期間で、何らかの困難な状態になって機能しないと困る場合
耐障害性 コンポーネントの障害が発生しても、それに耐えたり、回復させたりできること。 障害が考えられ、その際に耐えられなかったり、回復が遅いと困る場合
セキュリティ 悪意ある行為に対して耐性があること。 悪意ある行為が考えられ、それに耐性がないと困る場合
保守性 ある一定時間で、特定の状態に復帰できること。 特定の状態に復帰できないと困る場合
互換性 他の製品と相互にやりとりできること。あるいは、過去の代替すべき製品と互換であること。 他の製品と相互にやりとりできないと困る場合。過去の製品と互換しないと困る場合
モジュール性 モジュール性を考慮した設計。それによって保守性も向上する。開発においてもコンポーネント単位で実装し>テスト可能などの利点がある。また、開発作業の分割が容易になる。 モジュール化していないと困る場合。モジュール化したほうがメリットが有る場合
再利用 モジュール性がよければ、個々のコンポーネントを他の場面で再利用できる可能性が生じる。 再利用が必要な場合

昨今であれば巨大なシステムでもなければ、こういった設計が全て必要ということは稀だと思います。
実際考慮することはそこまで大変ではないかもしれません。

ただ、これ以外にも必要そうな設計は出てくるのではないでしょうか?

「困った」経験値が強さになる

当然、困る要因、知識がないと先回りして手を打てません。
そう考えると、経験豊富な人の方が上手く設計できるでしょう。
逆に初めて行うようなタスクにおいて設計するのは至難の業です。

「困る」をもう少し明確に

上で一回挙げたのですが

  • 元に戻せない
  • 完成しない(詰む)
  • 目標を達成できない
  • 矛盾が生じる
  • 進まなくなる

これらを「困ること」としました。
これ以外に「より良くなること」もあります。
「ポジティブ」か「ネガティブ」かという話と、要件を「満たすか否か」と「程度」の話ですね。

上手く設計するために

設計は正直答えがありません。それなのに重要度は非常に大きく、また個人の力量にかなり依存します。
設計できない人には、設計結果の良し悪しが判断できません。その設計が良かったかどうかはプロジェクトを進めてみるしかありません。

そんな大変な作業をいかに精度良くやるか考えてみます。

設計ができる条件

  • 似たプロジェクトの経験値があること
  • プロジェクトで何が起こるか予想できること
  • 要件が固まっていること

もちろん、初めて取り組む領域でも調査次第である程度は設計できるでしょうが、やはりカバー率は落ちると考えるべきでしょう。特に「どこからどこまで考えるべきか」で非常に悩むと思います。
なので大抵の場合は設計を経験者が行うと思います。または可能なら設計レビューを受けるべきです。

また、満たすべき要件がある程度固まっていないとそもそも何をしていいかわかりません。

設計する際に確認すること

  • ゴール、要件
  • より良い状態

sekkei2.jpg

まず何を満たすべきかどうなればより良いかを考えなければなりません。
もちろん設計対象に対してなので、プロジェクト全体のゴールや要件とも少しずれます。これは設計者が考え、プロダクトオーナーなどと確認しておくとよいです。
省略されがちですが、設計のドキュメントや成果物は、必ずそれが必要な理由が存在するはずです。その点を意識するだけでタスクが明確になると思います。

設計の失敗とは

  • 困る、破綻する(詳細は前述)
  • 困ることを予期できなかった
  • 予期していたけど、対策に効果がなかった
  • 何故そう決まったのか分からない

起こりがちなのが「何故そう決まったのか分からない」です。物によっては不必要な縛りをシステムに与えてしまいます。
「別に先んじてそれを決める必要がないことを決めてしまう」などということもよくあります。

「困ること」を洗い出すために

設計は完璧に行おうとすると、ありとあらゆることに考えを巡らせなければならない難しい作業です。
経験値勝負と、想像力勝負です。
例えば、対象の動作環境、特徴、どういう厳しい状況で動作しなければならないか、何年動いていなければならないか、何人で管理するのか、どういう頻度でアップデートするのか、どうなるとより良いのか、など色んな角度から想像して、こうなったら困るだろうというものを集めます。

周りや有識者に意見を求めることも重要です。設計には念を入れるべきです。

「それは困ったことではない」「それは想定しない」というラインを決めることも重要です。何もかも想定しすぎると、コストが重くなって何もできなくなります。どこかで妥協が必要で、それを詳細に詰めていくのも設計の役割です。

外部設計、内部設計

設計には、大きく分けて外部と連携するもの、内部だけで完結するものの二種類があります。
外部設計の場合、対象の内だけでは完結しないことがあります。相談や調査が必要です。
「外部」というと並列した何かだけを想像しがちですが「制約」と捉えたほうが理解しやすいかもしれません。システムの設計は例えば組織設計にも制約を受けますし、事業設計、プロダクト設計にも制約を受けるでしょう。

デザインパターン

設計は非常に難しいことがあるので、ある程度パターンになっていることがあります。いわゆるデザインパターンというやつです。

デザインパターンのメリット

  • 生まれた経緯を知ることで、そもそもどういう「困ったこと」が起こり得るかを知ることができる
  • 洗練されている

デザインパターンのデメリット

  • 目的に合っていないシーンで使用してしまうことがある

特に、元々なぜそれが生まれたかが置き去りにされて成長してしまったデザインパターンは、一度自分やチームの中できちんと咀嚼できないと却って悪影響が出がちです。いつの間にか「デザインパターンに沿っているか沿っていないか」が論点になってしまいます。

似たようなものとしてベストプラクティスがあると思いますが、こちらの方が何に対する解決策なのかが明確だと思います。

ソフトウェアにおける設計の特徴

他の業界の設計を考えると、ソフトウェアの設計は特殊に感じます。
何故なら、意外と後戻りできてしまうケースがあるからです。
例えば建築業界で設計ミスしたらどうなるでしょうか。商品開発で設計ミスしたらどうでしょうか。それらに比べたら、まだマシと思えることが多いのではないでしょうか。

いかに設計しないか

推測ですが、この業界はどんどんいかに設計しないかという方向に動いていると思います。途中で簡単に後戻りできたり、変更ができて「困らない」ことこそが事業の強さになっているわけです。

普段の設計でも同様で、全てを予測して決め打ちするよりは、いつでも困ったことに対処できる状態にする方がより安全なのかもしれません。
そのために必要なのは

  • 困ったことが起こる前、あるいは起こった時に検知する仕組み
  • すばやく対処する仕組み
  • そもそも困ったことにならない設計やサービスの活用
  • 複雑度を低く保つ

などがあるでしょう。
言ってしまえばこれらが新しい今風の設計なのかもしれません。

複雑度を低く保つには

すいませんが、長くなるので割愛

Designが重要と叫ばれている話

国内外のスタートアップ界隈で、昨今Designが重要だと叫ばれているのをご存知でしょうか。あれが果たして何故なのか、色んな方が思い思いに語られているのですが、私はこのエントリで大体説明できると思っています。
頭を柔らかくして考える必要がありますが。「困らないために、予め対応する」というのが設計(Design)だとすると、それをビジネスや世の中に当てはめ実行できることが重要であるのは、自明の理でしょう。その方法論をDesignと称しているわけです。

しかしここには罠があります。

  • その方法論は相当な経験値が必要
  • 設計者であなければ行使できない(たぶんそれはCEO)
  • デザインパターンにはデメリットもある

とは言え設計の考え方は重要ですし、色々と応用が利きます。
昨今のプロダクト開発は、システムが他のものと密接に結びついています。プロジェクトを成功させるためには頭を柔らかくして設計する必要があります。
特に「選択」「配置」「調整」「計算」が絡むものは「設計」を意識するべきです。
クラス設計もそうですし、組織設計もそうです。だんだん全部同じように見えてきます。全部同じに見えたら、設計の結果も変わってくるのではないでしょうか。

おわりに

まだ個人的に考えが甘い部分があると思っていますが一旦まとめてみました。
少なくとも「設計する」という言葉に怯えなくてよくなれた気がします。

よりコード側に近い話も考えているのですが、苦戦しているので分けたいと思います。