moduleという概念について、本人の許可を得てまとめたものです。本書の内容を詳しく紹介するのではなく、主に私の考察を書き綴ったものです。moduleという概念について説明します。良いモジュールとは良いモジュールとはなんでしょうか。ここでいうモジュールというのは、クラス・構造体やサブシステム、さらにマイクロサービス等の分化されたソフトウェアを指し、言語は問いません。beautiful」というUnix哲学があるように、小さいことは価値になります。モジュールを小さく分割することでモジュールの仕事が明確になりやすく、結果的に保守が容易になります。確かにそれは大切なことですが、そもそもなんのためにモジュールを作るのでしょうか?主な理由の一つとして、関係性の高い要素が集まることで実装の複雑さを下げるというものが挙げられます。それを踏まえた上でこのコードを見て下さい。Javaでファイルを開く際、以下のように3つの小さなクラスが必要です。gist.github.comFileInputStreamは初歩的なI/Oのみを提供し、BufferedInputStreamは、FileInputStreamで得られたバイト入力ストリームをバッファリング読み込み付きのバイト入力ストリームに変換します。ObjectInputStreamはシリアライズされたオブジェクトを操作する機能を提供します。見ての通りファイルを開くためだけに3つもオブジェクトを生成しなければなりません。クラスを小さくしたことで、各クラスの仕事は明確になりました。関連性の高いFileInputStreamとBufferedInputStreamが独立してしまっていることで、もしユーザーがBufferedInputStreamを作り忘れた場合はバッファリングされずに遅くなってしまいます。実装の複雑さが外部に漏れてしまっているということです。実装の複雑さが漏れることが必ずしも悪いとは限りません。以下のことは認識しておくべきです。beautifulであることは間違いないのですが、関連性の高い要素を分割してしまうと保守性が下がってしまうことが分かりました。小ささを意識しすぎると良いモジュールは作れないことが分かります。高凝集?疎結合?関連性の高い要素が集まり(高凝集)、それぞれが依存し合わない(疎結合)ことは非常に大切です。上記コードは低凝集・密結合の良い例です。関連性の高いたくさんの要素を隠し持つメリットはたくさんあります。"関連性の高い"要素を持つことで設計が明確になり、保守と拡張が容易になり、再利用性が高まります。"たくさんの"要素をもつことでモジュールの機能が強力になります。"隠し"持つことで疎結合化も促進することが出来ます。よって、高凝集というのは非常に大事な概念だということが分かります。モジュールの疎結合化がソフトウェアに良い影響を与えるのは言うまでもないでしょう。疎結合を保つためには、モジュールを繋ぐインターフェースを良いものにする必要があります。良いインターフェースとは「インターフェースはシンプルに保て」とよく言われますが、このシンプルという言葉は曖昧なので噛み砕いていきます。モジュールのインターフェースに何が求められているのかを理解する必要があります。モジュールが他のモジュールを利用するためには、インターフェースという名の契約を結びます。各モジュールは契約を前提に実装されるので、契約が変わるとその契約に関わっている全てのモジュールの実装を変更しなければなりません。ソフトウェアというものは、ほとんどの場合変更されます。この矛盾の中でも崩れないことがインターフェースには求められています。良いインターフェースとは、不変(追加以外の変更を許さない)なインターフェースだと考えています。可能な限り、インターフェースを利用するユーザーにとって使いやすくあるべきです。Mattersで述べていた考え方に影響を受けています。使いやすさというのは相対的な概念で、何が便利なのかはユーザーによると考えています。ユーザーをユースケースの観点で大きく2つに分けると、エッジケースで利用するユーザーと一般的なケースで利用するユーザーに分かれます。インターフェースが複雑になってしまう主な理由として、エッジケースを許容してしまうということが挙げられます。そのため、一般的なユースケースに絞って使いやすさを追求するべきです。先程のJavaのコードをもう一度見て下さい。ファイル操作時にはバッファリングするのが一般的なケースのはずです。関わらずBufferedInputStreamクラスを独立させることで、バッファリングしないというエッジケースを許容していました。そのためインターフェースが複雑化してしまったということです。良いインターフェースをまとめると、「一般的なケースで使いやすく不変なインターフェース」と考えることが出来ます。上記を踏まえて、私の考える良いモジュールの定義は「関連性の高いたくさんの要素を隠し持ち、一般的なケースで使いやすく不変なインターフェースによって強力な機能を提供するもの」です。moduleという概念について説明します。moduleたくさんの要素を隠し持つためには、ある程度実装は複雑になります。良いモジュールにするためには、実装の複雑さを感じさせないインターフェースで強力な機能を提供しなければなりません。moduleと呼んでいます。本書では以下のように書かれています。modules上図は本書に記載されている図を参考に作成したものです。長方形が一つのモジュールを表しています。上端の横の長さがインターフェースの複雑さを表していて、縦の長さが機能の強力さ(モジュールがもたらす利益)を表しています。横に長ければ長いほどインターフェースが複雑で、縦に長ければ長いほど機能が強力だということです。Ousterhout教授は左の縦長な長方形のようなモジュールをdeepと表現しており、最も良いと考えています。モジュール設計の際には以下の視点が必要だということです。機能は強力だけど、インターフェースも負けないくらい複雑になっていないか?逆にインターフェースは簡単だけど、機能も負けないくらい貧弱ではないか?インターフェースの複雑さというのはコストで、機能の強力さというのは利益です。moduleといえます。この見極めが難しいので、良い例をたくさん見ることが大切です。moduleを体現している例として、Unix系OSのファイルI/Oに関わるシステムコールが挙げられます。標準的ファイルI/Oモデルから外れなければ、使うシステムコールは基本的に以下5つのみです。I/Oの実装は長年に渡って進化し続けているのにも関わらず、この5つのシステムコールは変わっていません。moduleといえます。カーネルは本来ユーザアプリケーションを安定して動作せるために設計されているため、インターフェースがほとんど変わりません。そのため、カーネル周辺のインターフェースをじっくりと眺めてみると参考になると思います。抽象的な世界をコードに落とし込む上に常に変わり続ける「ソフトウェア」というものに、全ての視点を取り入れるのは困難だということは誰もが感じているはずです。moduleについて、一人でも多くの方が理解して頂けたら幸いです。興味を持った方は本書を購入することを強くオススメします。moduleについて知った時、以下ツイートのようなことを考えました。これについては別エントリでまとめるかもしれません。これを読んでたら「良いモジュールは簡単なインターフェースで多くの機能を提供してくれる」と強調されており、任天堂の宮本さんの「アイデアとは複数の問題を一気に解決するもの」という言葉を思い出した。2019年1月6日*間違いやご意見等ありましたら、Twitter等で連絡して頂けると大変助かります。(2)月別アーカイブはてなブログをはじめよう!NakaWatchさんは、はてなブログを使っています。ブログを報告するスターをつけました引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。