パッケージ命名規則って何のためにあるのか
パッケージ名は
「このコードはどこの誰が書いた、何のグループなのか」
を表すラベルです。
クラス名が「1人の役者の名前」だとしたら、
パッケージ名は「その人が所属している部署・チーム・モジュールの名前」です。
命名規則をちゃんと考えておくと
どこに何のコードがあるかが一瞬で分かる
クラス名の衝突を避けられる
プロジェクト全体のフォルダ構成がスッキリする
というメリットがあります。
逆に適当に付けると
同じような名前のパッケージが増える
どこにクラスを置けばいいか迷う
パッケージが「ゴミ箱」になっていく
という、長期的にかなり痛い状態になります。
Java の基本ルール(逆ドメイン+すべて小文字)
逆ドメイン形式の意味
Java の世界では、パッケージ名は「逆ドメイン」が基本です。
例えば、あなたの会社や個人サイトのドメインがexample.com なら com.examplemyapp.jp なら jp.myappgithub.io/yourname 系なら io.github.yourname
という形からスタートします。
なぜこうするかというと
「世界中の Java プロジェクトでパッケージ名がかぶらないようにするため」です。
みんなが app.user とか main.service とか好き勝手に使うと、
他のライブラリと組み合わせたときにクラスのフルパスが衝突しやすくなります。
逆ドメインにしておけばcom.example.app.user.Userjp.co.foo.app.user.User
のように、トップの部分でまず絶対に違ってくれるので安全です。
小文字スネークではなく「小文字ドット区切り」
Java のパッケージ名は、基本全部小文字を使います。com.example.myapp.domain.user のような形です。
クラス名は UserService のようにキャメルケースですが、
パッケージ名は user や userdetail のように小文字だけで書くのが慣例です。
com.Example.App.User のように大文字を混ぜると、
Java の世界ではかなり違和感のある見た目になるので避けましょう。
アプリケーション部分の切り方(技術軸と機能軸)
技術軸で切るパターン
よくあるのが、技術やレイヤごとにパッケージを切るパターンです。
例えば Web アプリなら
com.example.myapp.controllercom.example.myapp.servicecom.example.myapp.repositorycom.example.myapp.domain
のような形です。
コントローラは controller、
サービスは service、
DB アクセスは repository、
ドメインのモデルは domain、
といった感じで、レイヤごとにディレクトリを分けます。
このスタイルの良いところは
「このクラスって何層のもの?」がパッと見で分かる
新しくクラスを作るときに、どのフォルダに置くか迷いにくい
という点です。
ただ、機能が増えるほど
controller パッケージにコントローラが大量に並ぶ
service パッケージにサービスが大量に並ぶ
という「同じ種類のクラスがだだっ広く並ぶ感じ」になりがちです。
機能軸(ドメイン軸)で切るパターン
もう一つのやり方は、「機能(ドメイン)」ごとにパッケージを切るやり方です。
例えば EC サイトなら
com.example.shop.usercom.example.shop.ordercom.example.shop.productcom.example.shop.payment
のようにします。
その中に Controller や Service をまとめて置きます。
com.example.shop.order.OrderControllercom.example.shop.order.OrderServicecom.example.shop.order.OrderRepositorycom.example.shop.order.Order
というイメージです。
こうすると
「注文まわりのコードは全部 order パッケージにいる」
と分かるので、仕様変更やバグ調査のときに、見るべき範囲を狭くしやすいです。
個人開発や中規模くらいまでのプロジェクトなら
ドメイン(機能)軸でパッケージを切るほうが、
オブジェクト指向的にはしっくり来ることも多いです。
名前をつけるときの考え方(ここが本質)
そのパッケージは「何の話題の集まりか」を一言で言えるか
パッケージ名を決めるとき、まず日本語で
「ここには何に関するクラスを集めるのか」
と自分に聞いてください。
「ユーザ管理に関するもの全部」なら user
「注文全般」なら order
「認証・認可まわり」なら auth
「支払い・決済」なら payment
といった感じになります。
逆に、以下のようなパッケージ名は危険信号です。
commonutilhelpermiscother
これらは「何でも入れていいゴミ箱」になりがちです。
例えば common.util みたいなパッケージができると、
最初は便利に見えますが、そのうち
どこの機能にも属さない、よく分からない便利クラスたち
どこに置けばいいか分からなかったクラスたち
の墓場になります。
「このパッケージ名を見て、そこに何があるか説明できるか」
を自分に問いかけるのが大事です。
パッケージ名に「役割・層」を含めるかどうか
先ほどの技術軸と機能軸を組み合わせることもできます。
例えば
com.example.shop.user.webcom.example.shop.user.applicationcom.example.shop.user.domaincom.example.shop.user.infrastructure
のように、「user(機能)」の下に層をぶら下げるスタイルです。
DDD(ドメイン駆動設計)寄りのプロジェクトだとよく見かける形です。
最初からここまで細かく分ける必要はありませんが、
少なくとも
user なのか order なのかweb なのか domain なのか
くらいはパッケージ名に出ていると、迷いが減ります。
良くない例から学ぶパッケージ命名の落とし穴
なんとなくその場しのぎで増えていくパッケージ名
例えば、次のような構成を想像してみてください。
com.example.app.maincom.example.app.subcom.example.app.sub2com.example.app.newmain
この状態で、新しい機能が増えるたびに
どこに置けばいいか分からない
とりあえず main か sub に入れておく
そのうち newmain ができる
というカオス状態になりがちです。
パッケージ名に「main」「sub」などの相対的な名前を付けると、
時間が経つほど意味が失われていきます。
「これはユーザの話なのか」「注文の話なのか」
そういう「テーマ」や「ドメイン」が見えない名前は避けた方がいいです。
フレームワーク名や技術名をトップに出しすぎる
例えば Spring Boot を使っているからといって
com.example.spring.usercom.example.spring.order
のように spring をパッケージ名に含めるのは、あまり意味がありません。
フレームワークはあくまで実装技術であって、
アプリケーション自体の本質は「何の業務を扱っているか」です。
spring, mysql, jdbc, rest などの技術ワードは
「もう少し下の階層」に閉じ込めておくのが無難です。
例えば
com.example.shop.order.infrastructure.jpa
のように、「order のインフラ層で jpa を使っている」という粒度で出てくるのは自然です。
実際の例でイメージを固める
シンプルな小規模アプリの例
例えば「本の貸し借り管理アプリ」を作るとします。
最初はこんな感じが無難です。
com.example.library.bookcom.example.library.usercom.example.library.loan
book には Book や BookRepository
user には User や UserRepository
loan には Loan(貸出)や LoanService
などを置きます。
Web フレームワークを使っているなら
com.example.library.book.web
に BookController を置く、などのように、機能の下に層を分けていくイメージです。
「最初から完璧」は目指さなくていい
現実的には、最初から完璧なパッケージ構成なんて無理です。
大事なのは
少なくとも「何の話題か」はパッケージ名から分かるようにしておくcommon や util のようなゴミ箱パッケージを安易に作らない
増えてきたら「今の分け方でまだ説明できるか?」を定期的に見直す
という姿勢です。
パッケージ名を変えるのは IDE のリファクタリングで比較的安全にできます。
「おかしいな」と思った時点で早めに整えると、後々の負債がかなり減ります。
まとめ:パッケージ名を決めるときの自分への問い
パッケージを新しく作るとき、あるいは名前を迷ったときに、
短く自分にこう聞いてみてください。
このパッケージには、どんな“話題”のコードを集めるつもりか
その話題を、日本語で一言にすると何か(ユーザ? 注文? 支払い?)
それを英語の名詞にしたパッケージ名になっているかcommon, util, misc に逃げていないか
ドメインの言葉がパッケージ名にちゃんと反映されているか
