パッケージ(ライブラリ、アプリケーション、モジュール)を作る際、どの単位でパッケージを分割するかを考えてみます。
パッケージとは
パッケージが何を指すかを先にお話しします。
ここでいうパッケージは node.js の npm や、 php の composer でいうパッケージと同等の意味です。java でいうと maven のモジュールにあたります。
パッケージはライブラリの場合もあれば、実行可能なアプリケーションの場合もあります。
なぜパッケージを分割するか
あるシステムを作る際、パッケージを分割せずに作るといわゆるモノリス1巨大な一枚岩。「2001年宇宙の旅」で登場するモノリスから転じて、地球人に理解できるような代物ではないという嫌味も含まれるとか含まれないとか。と呼ばれる巨大なパッケージが誕生します。パッケージはもともと小包という意味なので、巨大なパッケージというのはおかしな言葉ですね。
パッケージが巨大化するといくつか不都合が起きます。1つめはソースファイルが多くなるので IDE での操作やビルドに時間がかかるという点です。
2つめは再利用性が低くなる点です。モノリスの一部実装を他のシステムでも利用したいとなった場合、モノリス全部を参照するようにすると余計な機能までついてきてしまいます。
生産性をあげ、かつ再利用可能なコンポーネントを作るためにパッケージの分割は不可欠です。
分割を検討する単位
私の場合、パッケージを作成する際は、以下の軸から考慮することが多いです。
- 実行環境軸
- 機能軸
- 依存関係軸
- インターフェースと実装
実行環境軸
これは分割するというより分割せざるをえない単位です。
- フロントエンド (Webアプリ、スマホアプリ)
- バックエンド(REST API など)
フロントエンドのアプリにバックエンドの処理を一緒に載せることはないですし、そもそも開発言語が違ったりするので必ず分かれてきます。
機能軸
ここで機能というのは人間から見た機能のことを言います。ユースケースを元にしたドメイン単位です。アプリケーションはこの方法で分けることが多いです。
WordPress の場合は以下のような具合です。
- 投稿
- メディア
- 固定ページ
- コメント
- ・・・
管理画面のメニューの分類です。これごとにパッケージを切るという方法です。
依存関係軸
依存関係によってパッケージを切る方法です。ライブラリはこの方法で切ることが多いです。
アプリケーションから参照されるライブラリを作成する場合を考えてみます。今回はブログの投稿機能とコメント機能で考えてみます。
- このシステムは HTTP による入出力とメール送信を行います。そのため HTTP とメールのライブラリに依存します。
- 投稿機能とコメント機能のアプリケーションを作成し、それらで共通して使う処理を共通ライブラリとしてパッケージ化することにしました。

ここで、 HTTP は「投稿機能」でも「コメント機能」でも利用するので問題ないのですが、メール送信処理は「コメント機能」でしか利用しないことが判明しました。しかし「コメント機能」は「共通ライブラリ」に依存し、「共通ライブラリ」は「メールライブラリ」に依存しているため、使用しない「メールライブラリ」を参照してしまいます。
これは無駄なので次のように「共通ライブラリ」を依存するライブラリごとに分割します。

こうすることで必要最小限の依存関係となり、開発時や実行時のパフォーマンス改善が見込まれます。
インターフェースと実装
インターフェースの必要性についての説明は本筋から外れるので省かせてもらいますが、疎結合の実現のために以下の3つの役割でパッケージを分割するという方法です。
- ある機能を利用するパッケージ
- ある機能を提供するパッケージ(実装)
- ある機能を利用するために必要な入力と、提供される出力を定義する契約(インターフェース)
具体的な例を挙げると java だと Jakarta EE のようなものです。JPA という ORM の仕様(インターフェース)があり、それを実装する Hibernate や Eclipse Link などが存在し、私たちはそれを利用してアプリケーションを組み立てるというような分担でパッケージを分割します。
所感
最近、クラウドやマイクロサービス、コンテナ技術を調べていたのですが、アプリケーションのサイズを減らすことがコスト・パフォーマンス面で重要であることが分かりました。パッケージ分割でよりアプリケーションのサイズを最適化していければと思います。