Help us understand the problem. What is going on with this article?

PlayFrameworkでプロジェクトを分割する

More than 3 years have passed since last update.

はじめまして。Qiita初投稿の t_hirohata です。
よろしくお願いいたします。

弊社ではScalaで開発しており、最近ではDDDで設計しようという動きになっています。
新しくプロジェクトを作る際DDDの各レイヤ毎にプロジェクトを分割したので、その方法をご紹介させていただきます。

方針

今回作成するプロジェクトはレイヤードアーキテクチャで設計したため、以下の様な構造に分割します。

projectRoot
  ├─ application
  ├─ domain
  └─ infrastructure

また、

  • アプリケーション層はPlayアプリケーションでいいけど、ドメイン層・インフラストラクチャ層はPlayに依存させたくない・・
  • 上層から下層は呼び出せるけど、下層から上層は呼び出せないようにしたい・・

としたかったため、以下の方法で実現しました。

プロジェクト分割

build.sbt
// このプロジェクトはapplication、domain、infrastructureの集合である
lazy val root = (
  project in file(".")
).aggregate(
  application,
  domain,
  infrastructure
)

// アプリケーション層
// アプリケーション層はドメイン層・インフラ層に依存し、Playアプリケーションである
lazy val application = Project(
  id = "application",
  base = file("application")
).dependsOn(
  domain,
  infrastructure
).enablePlugins(
  PlayScala
)

// ドメイン層
// ドメイン層はインフラ層に依存
lazy val domain = Project(
  id = "domain",
  base = file("domain")
).dependsOn(
  infrastructure
).settings(
  scalaSource in Compile := baseDirectory.value / "src" / "main" / "scala",
  scalaSource in Test := baseDirectory.value / "src" / "test" / "scala"
)

// インフラ層
lazy val infrastructure = Project(
  id = "infrastructure",
  base = file("infrastructure")
).settings(
  scalaSource in Compile := baseDirectory.value / "src" / "main" / "scala",
  scalaSource in Test := baseDirectory.value / "src" / "test" / "scala"
)

これでビルドしてみると以下の様な構造になります。(もともとあったものを除く)

projectRoot
  ├─ application
  │     ├─ app/
  │     ├─ conf/
  │     ├─ public/
  │     └─ target/
  ├─ domain
  │     ├─ src/
  │     └─ target/
  ├─ infrastructure
  │     ├─ src/
  │     └─ target/
  ├─ project/
  ├─ target/
  ├─ activator
  └─ build.sbt

これで今回作成したかったものを実現できました。

実行方法は以下の通りです。

$ ./activator "project application" run # ./activator "application/run" でも可

上記は、下記と同じです。

$ ./activator
[projectRoot] project application
[application] run

UI層について

あれ?UI層が分離できていないじゃん。と思う方もいらっしゃるかもしれません。
今回作成したもののアプリケーション層はPlayアプリケーションとなっており、ControllerとViewが分かれていますので、それで妥協しております。
妥協せずにやるのでしたら、アプリケーション層はただJSONを返すだけのRESTfulなAPIサーバとして実装し、UI層をPlayのViewではなく別で実装する方法が良いと思います。
そうすることによって、Android、iOS、WebなどのUIを別々に作ることができ、ドメインを使いまわせることになります。

最後に

長々と書いてしまいましたが、Playでプロジェクトの分割、ついでに依存関係の強制の方法についてご紹介させていただきました。
まだまだペーペーのエンジニアなので至らぬ点があるかもしれません。
ご意見・ご指摘等ございましたら、お気軽にコメントお願い致します。

septeni-original
技術を磨き続けることでネットサービスを軸とした新たな体験を世界に提供します。
http://www.septeni-original.co.jp/index.html
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away