⚙️

モジュールとは何か?

2024/05/28に公開

https://blog.starbug1.com/archives/2803 のミラーです。

様々な設計原則やデザインパターンの中でモジュールという言葉が登場します。モジュールという言葉の意味は「部品」のようなイメージはありそうです。しかし、それ以上明確な定義を求められると困ってしまうかもしれません。

モジュールというのは、どう捉えるべき概念なのでしょうか?

Wikipediaで見るモジュール

例によってWikipediaではどのように説明しているかを調べてみます。モジュールのページからソフトウェア工学から見たモジュールからの引用です。

モジュールはサブルーチンとデータ構造の集合体としてのソフトウェアの実体である。モジュールはその部分だけでコンパイル可能な単位でもあり、再利用可能であると同時に、複数のプログラマが同時並行的にそれぞれ異なるモジュールの開発を行うことが可能となる。モジュールの特徴として「モジュール性」とカプセル化があり、それらによって複雑なプログラムを理解しやすくできる。
モジュールはインタフェースと実装を分離する。モジュールのインターフェイスはそのモジュールが外部に提供すべき要素とそのモジュールが必要とする要素を表している。実装はそのインターフェイスで提供するよう定義された機能を実際に実現するコードを含む。モジュールの概念を明示的にサポートする言語として、Ada、D言語、F言語、FORTRAN、Pascal、ML、Modula-2、Python、Ruby などがある。

https://ja.wikipedia.org/wiki/モジュール

上記を非常に簡単に要約すると、「モジュールはそれぞれ別々に開発可能であり、複雑なプログラムを理解しやすいものにするのを助ける。モジュールはインターフェースを提供する」となります。

明確な定義としては納得できるものに感じますが、モジュールという概念が曖昧な人にとっては理解が難しそうです。なので、ここからは、私見多めでモジュールについて考えてみます。

モジュール構造の具体例

まずは、モジュールとして捉えることができる構造にはどんな具体例があるかをリストアップします。構造の特徴(境界/インターフェースとしてのデータと振る舞い)について考えます。

個別のライブラリのように単体で提供され、自分のアプリケーションに後から導入することが可能なもの

言語のパッケージマネージャ等(composer, npm)で提供されているものは、モジュールの一番分かり易い構造です。

  • 言語のパッケージマネージャ等によりダウンロード可能になっているディレクトリが境界になります。
  • 公開された構造体やクラスのプロパティが、モジュールが提供するデータとなります。
  • 公開された関数やクラスのメソッドが、モジュールが提供する振る舞いになります。

アプリケーション内の複数の場所から使う機能郡が特定のディレクトリに配置されているもの

平たく言うとアプリケーション内の共通機能という位置付けとなっているものが該当します。

  • 言語機能にネームスペースがあれば、ネームスペースを境界としています。
  • 公開された構造体やクラスのプロパティが、モジュールが提供するデータとなります。
  • 公開された関数やクラスのメソッドが、モジュールが提供する振る舞いになります。

クラス

単一のクラスも立派にモジュールの要件を満たしています。

  • クラスが境界となります。
  • クラスのプロパティはデータです。
  • クラスのメソッドは、振る舞いです。

関数

かなり無理がありますが、関数も見方に依ってはモジュールの見做せる側面があるかもしれません。

  • (境界は曖昧です)
  • 関数の引数と戻り値をデータと見做すことができます。
  • 関数は、振る舞いと見做すことができます。

再帰的な構造になるモジュールの関連の具体例

次に、具体的な処理の流れを例に、モジュールとして捉えることができる部分がどこにあるか探してみます。

ユーザー情報登録クラスの処理で、身分証明書をAWS S3に格納するという要件があった場合の実装例をシーケンス図にしたものです。

ユーザー情報登録クラス

ユーザー情報登録クラスは、名前やメールアドレスなどの情報を登録するためのクラスです。この処理の中で身分証明書も登録することになっており、アップロードされた身分証明書の画像ファイルは、上記で記載した要件のとおりAWS S3に保存することになっています。身分証明書のアップロードは、アプリケーション内で作成された身分証明書アップローダーを使って行います。身分証明書アップローダーは、ユーザー情報登録クラスの開発者に対してモジュールとして機能を提供していると言えます。

身分証明書アップローダー

身分証明書アップローダーは、身分証明書に特化したアップローダーです。指定されたファイルをaws-sdkを使って、S3にアップロードします。aws-sdkは、身分証明書アップローダーの開発者に対してモジュールとして機能を提供していると言えます。

aws-sdk

aws-sdkは、プログラミング言語毎にAWSの機能を利用するためのモジュール郡を提供しています。ここから先は普段は意識していないかもしれませんが、aws-sdkはAWSのサーバーとHTTP通信を行なうため、GuzzleHttpを使用しています。GuzzleHttpは、aws-sdkの開発者に対してモジュールとして機能を提供していると言えます。

このように、モジュールとして見做していた一つの要素が、視点を変えると他のモジュールを利用する側になるという事がわかります。

モジュールの存在する場所

これらのモジュール構造、モジュール階層が全てモジュールの構造であるとすると、アプリケーション内には、ありとあらゆる部分にモジュールの構造が無数に再帰的に存在するという見方ができます。

https://commons.wikimedia.org/wiki/File:Sierpiński_triangle.svg 最終編集, CC BY-SA 4.0 https://creativecommons.org/licenses/by-sa/4.0, via Wikimedia Commons

画像は、再帰的な構造を表現したフラクタル図形の一種です。

シェルピンスキーのギャスケット(英: Sierpinski gasket、波: uszczelka Sierpińskiego)は、フラクタル図形の1種であり、自己相似的な無数の三角形からなる図形である。

シェルピンスキーのギャスケット

モジュールとは

ここまで考えてきた内容を踏まえて、改めてモジュールというものについて説明してみます。

まず、特殊な問題が存在します。全ての開発者がその問題を解決するのは様々な意味で無駄なので、代表してある開発者がその問題を解いて解法を纏めておいて、他の開発者はその解法を使うことで簡単に同じ問題を解決できるようにするのが望ましいです。

モジュールとは、上記のような文脈で、特殊な問題を解決するための機能を提供する、明確な境界を持った機能の纏まりです。モジュール提供者が公開したインターフェースを使って、他の開発者はモジュールを利用することができます。

また、モジュール提供者とモジュール利用者は、互いに利害関係にあると言えます。

モジュール提供者の気持ち

  • モジュール利用者に便利に使ってもらいたい
  • モジュール内部が制御不能になる程複雑になってしまっては困る
  • 機能追加等の修正をしても新たな不具合が発生しないようにしたい

モジュール利用者の気持ち

  • モジュール内部の細かい事情を知らずに、簡単にモジュールを利用したい。
  • とは言え、利用者が望むバリエーションには対応して欲しい
  • 時には、機能追加して欲しいこともあるかも

利害関係にある2者の間で、トレードオフを探ることが設計と言えるかもしれません。

もちろん、一人で一つのアプリケーションを開発している場合でも、プログラムの理解可能性や保守性を高めるために、モジュールの考え方により、適切にモジュール分割を行ないます。この場合でもモジュールの提供者と利用者という2つの帽子をかぶり分ける事を意識してモジュールを作り/使うことが、より良いモジュールを設計することに繋ると思います。

※「2つの帽子をかぶり分ける」は、Kent Beck のリファクタリングの説明で出てくる比喩です。機能追加の帽子とリファクタリングの帽子の対比でした。このブログ記事では、モジュール提供側の帽子とモジュール利用側の帽子を意図しました。 Chap.2 リファクタリングの原則

まとめ

今回は、モジュールについて考察してみました。モジュールという言葉の解像度に変化があったら嬉しいです。

様々な設計原則などでモジュールについての言及がありますので、これを踏まえて設計原則を見直してみるのも興味深いかもしれません。

Discussion