システムを作っていると、こんな悩みはありませんか?
- クラスやフォルダが増えてきて、どこに何があるか分からない
- 修正するとき、影響範囲が全然読めない
- 「とりあえずServiceに書く」文化で、Serviceが巨大化している
これは多くの場合、
「何の単位で分けるか」が決まっていない
ことが原因です。
この記事では、設計初心者でも迷いにくくなる考え方として、
「業務」と「役割」で分ける
というシンプルな方法を紹介します。
まずは「業務」で分ける
最初にやることはとても単純です。
「この処理は、何の業務なのか?」を日本語で言えるようにする
例えば:
- ユーザ登録
- 注文作成
- メール送信
- バウンスメール監視
こうした「業務名」を、そのままフォルダ名にします。
app/
user_register/
order_create/
mail_send/
bounce_monitor/
これだけで、
- 「注文作成の不具合」→ order_create フォルダを見る
という探し方ができるようになります。
次に「役割」で分ける
業務フォルダの中は、「役割」で分けます。
役割とは:
- 入口(画面・API・バッチ)
- 業務の流れ
- 業務ルール
- DBアクセス
- 外部連携
です。
例えば「注文作成」の場合:
order_create/
OrderCreateController ← 入口
OrderCreateUsecase ← 処理の流れ
OrderCreateDomain ← 業務ルール
OrderCreateRepository ← DB
OrderCreateExternal ← 外部連携
それぞれ何を書くの?
Controller(入口)
- 画面やAPIの受付
- パラメータを受け取るだけ
- 業務処理は書かない
Usecase(流れ)
- 「何を、どの順番でやるか」を書く
- if文、try-catch、トランザクション制御
public void createOrder(req) {
domain.validate(req);
repo.save(domain.create(req));
external.notify(...);
}
Domain(業務ルール)
- 業務として正しいかを判断
- 業務用語で説明できる処理
例:
- 金額は0円以上であること
- この状態ではキャンセル不可
Repository(DB)
- SQLやORMだけ
- 業務判断はしない
External(外部連携)
- APIや別サービスの呼び出し
- 通信の詳細を隠す
共通処理はどうする?
全部を共通化すると、逆に分かりにくくなります。
ルールはこれだけです:
- どの業務でも同じ意味で使える → common
- その業務だから意味がある → 業務フォルダ
common/
util/
exception/
log/
例えば:
- 日付変換 → common
- 「注文金額計算」→ order_create 配下
よくある失敗
① 役割だけで分ける
controller/
service/
repository/
→ 業務が見えなくなる
② 何でもServiceに書く
UserService
OrderService
MailService
→ どこが何をしているのか分からない
まとめ
初心者が迷わないための設計ルールは、とてもシンプルです。
- まず「業務」でフォルダを切る
- その中を「役割」で分ける
- 業務の意味がある処理は業務配下
- 本当に共通なものだけ common
つまり:
<業務>/<役割>/<クラス>
この形を意識するだけで、
- 探しやすい
- 影響範囲が分かりやすい
- 将来の修正が楽
という、長く使える設計になります。