Javaパッケージの分割、命名についてのまとめ。

Java: The Good Parts

Java: The Good Parts

JavaTheGoodPartsを読み終わったので、良いタイミングと思い、パッケージの分割、命名に付いてまとめてみました。

パッケージとは

Javaのパッケージとは、名前空間を作成するものである。 クラス名に一意な名前を指定する必要があるので、重ならないドメインを使用してパッケージ名を決定するのは基本だと思います。

パッケージ分割指針

レイヤでの分割

私は通常、Webアプリケーションを4層構造(view, controller, service, model)で作成し、クライアント側とサーバ側はJSONでやり取りすることが多いため、以下の様なパッケージ構成になります.私はある程度、大規模なシステムを作る場合が多いのでservice層を挟んでいますが、小規模な場合はserviceを省きます。

com.inoti.sample --- model
                  |
                  |- repository
                  |
                  |- service
                  |
                  |- contorller 
                  |
                  |- util

因みにこのService層の概念は、DDD(Domain-Driven Design)のものです。 詳しくは、以下の本を見ると良いです。

エリック・エヴァンスのドメイン駆動設計 (IT Architects’Archive ソフトウェア開発の実践)

エリック・エヴァンスのドメイン駆動設計 (IT Architects’Archive ソフトウェア開発の実践)

機能ごとに分けず、層で分けているのは、依存関係を一方向のみに集約させ易い(controller -> service -> model)からですね。非循環依存関係の原則って奴です。依存する対象が少ないパッケージはその分、システムの変更に強くなり、安定したパッケージとなります。 repositoryはデータストア部分を受け持つ部分です。aop等の共通処理がある場合は、aopパッケージを並列に追加します。

インタフェースと実装

インタフェースと実装のパッケージをどう分けるか、というのも悩みどころではないでしょうか。 私は基本、インタフェースをトップレベルパッケージに置き、そのサブパッケージに機能の分類として実装を置くようにしています。 この方が機能が分かれているので分かりやすく、Jarとして一部分の機能を切り出すときもやり易いと思います。 又、別の開発者が別の実装を作成する場合も、共通リソースを探しやすいのも利点です。

特に機能が分類される事が無く、デフォルトの実装のみ存在する場合は同一パッケージに置きます。 implパッケージはインタフェースが非常に多い場合に使用するくらい。

上記の例だとcontroller, service, modelなどはインタフェース、実装を同一パッケージに置き、repositoryでjdbcを使う場合、jpaを使う場合など、分けることが多いです。

com.inoti.sample --- model
                  |
                  |- repository 
                  |   |
                  |   |- jdbc
                  |   |
                  |   |- jpa
                  |
                  |- service
                  |
                  |- contorller 
                  |
                  |- util

例外

最後に、例外のパッケージです。 最近のWebアプリケーションではほとんどすべての場所でシステム用のRuntimeExceptinを使用し、Contorllerで全てキャッチするのをよく見かけます。 その場合、以下の様にexceptionパッケージが存在し、そこにシステム用のRuntimeExceptionが配置されていたりします。

com.inoti.sample --- model
                  |
                  |- repository 
                  |   |
                  |   |- jdbc
                  |   |
                  |   |- jpa
                  |
                  |- service
                  |
                  |- contorller 
                  |
                  |- util
                  |
                  |- exception

これはこれでシンプルで良いと思うのですが、例外に対するリカバリが行えないため、強いシステムにはなりません。 そこで検査例外を使うのですが、これもそのままexceptionに置いてあるアプリを良く見かけます。 これらの検査例外は大抵どこかのパッケージに依存しているので、そのパッケージ内に置くほうが良いと思います。

まとめ

パッケージ分割は、レイヤ分割、機能分割など、大まかな部分では共通すると思うのですが、細かな部分では個人の趣味が出るので指針をまとめてみました。