みなさんは、アプリケーション内の名前空間をどういったポリシーで分けていますか? (ここでは Java プログラムのパッケージ分割について考えることにしましょう) パッケージの分割方法、命名方法は、ベテランのプログラマでも悩むところです。
例えば、MyApp (com.example.myapp) というアプリケーションのルートパッケージが、下記のように分割されていたとします。
com.example.myapp
+ optionmenu
+ view
+ ...
このパッケージ分割方法には少々問題があるということにすぐに気付いた方は、普段から保守性を意識したコーディングを行えている人だと思います。 上記のパッケージ名からは、次のようなことを想像できます。
optionmenu
パッケージに格納すればよさそうだ。view
パッケージに格納するのだろう。でも、オプションメニューを構成する UI コンポーネントは optionmenu
に入れるの?それとも view
に入れるの?ようするに、パッケージ分割のポリシーがあいまいだということです。
optionmenu
というパッケージは、「アプリ内の部分的な機能」という側面 (aspect) に注目して分割しており、一方で、view
というパッケージは、「クラスが提供する機能の種類」という側面で分割してしまっています。
そもそも、物事は複数の側面(アスペクト)から捉えられるのに、名前空間は階層構造という概念でしか分割できないというところに制約があります。 ブログなどのシステムでは、タグという機能によって、記事に対して横断的なラベルを付けらるのですが、プログラミングの名前空間の世界には、このような機能は今のところありません。 どのような側面によりパッケージ分割するかのポリシーを決めておかないと、先の例のようなあいまいなパッケージ分割が行われることになってしまいます。 重要なのは、新しいクラスを作成するときに、どのパッケージに格納すべきかが直感的に分かるようなパッケージ分割のポリシーを決めることです。
ここでオススメするのは、「アプリ内の部分的な機能」を基準にパッケージ分割していくという方法です。 例えば、アプリケーションのルートパッケージを下記のように分割します。
com.example.myapp
+ feature(あるいは function など)
+ common
+ main(あるいは app など)
+ ...
feature
パッケージには、アプリケーションを構成する部分的な機能(フィーチャ)を提供するためのパッケージ、クラスを格納する(例: feature/opetionmenu
)。common
パッケージには、上記の複数のフィーチャから共通で使用するユーティリティクラスなどを格納する。main
パッケージには、アプリケーションを動作させるのに必須なクラスを格納する(起動シーケンスに関わる部分など)。モジュール化を意識するのであれば、main
パッケージはできるだけ小さく維持すること。このように分割しておけば、例えば、オプションメニュー機能の UI を構成するクラスは feature/optionmenu
パッケージ以下に格納すればいいんだな、とか、一方で共通で使用する UI モジュールは common/view
パッケージ以下に格納すればいいんだな、と一発で分かるようになります。
この分割方法は、複数メンバから構成されるチームで 1 つのアプリケーションを作っていくときに威力を発揮します。
ある機能を担当するメンバは、feature
以下の機能用パッケージでの修正に集中し、必要に応じて common
パッケージにある共通クラスを利用する、というように作業範囲を明確に絞り込めるようになります。
1 つのシステムは、複数のアプリケーションから構成されています。 これは、1 つのシステムがアプリケーションという「機能」単位に分割されていることにほかなりません。 この考え方を、アプリケーションの中の構造にも適用するということです。
例外は、ライブラリです。ライブラリ内のパッケージ構成は、「クラスの提供する機能の種類」で分割した方が利用者にとってわかりやすい構成となるでしょう。例えば、UI コンポーネントであれば、ui
や view
というパッケージにまとめて入れる、という具合です。