PHPerによるScala入門その3 sbt

昔はsimple build toolの略だったそうですね。全然simpleじゃねーだろということで変わったとか。

sbt

入門者向けの記事とか見てるとbuild.sbtってすごく簡素なんだけど、勉強用のリポジトリのやつも今のところこんなんだし。

name := "queue"
scalaVersion := "2.12.6"
version := "1.0"
scalacOptions ++= Seq("-deprecation", "-feature", "-unchecked", "-Xlint")

libraryDependencies ++= Seq(
  "org.scalatest" %% "scalatest" % "3.0.5" % "test",
  "org.mockito" % "mockito-core" % "2.13.0" % "test",
  "com.typesafe.akka" %% "akka-http"   % "10.1.8",
  "com.typesafe.akka" %% "akka-stream" % "2.5.19",
  "com.typesafe.akka" %% "akka-http-spray-json" % "10.1.8",
  "com.typesafe.scala-logging" %% "scala-logging" % "3.9.2",
  "ch.qos.logback" % "logback-classic" % "1.2.3",
)

scalacOptions ++= Seq("-deprecation", "-feature", "-unchecked", "-Xlint")

ここについては社内のリポジトリからパクったやつなのでちゃんと意味は分かってないがなんとなく想像つくので入れてみている。

それで、入門記事とか見てこういう風に書くというのを知った後でちゃんとしたプロジェクトのbuild.sbtを見に行くと全然読めない。

lazy val foo = (project in file("."))
  .settings(
    name := "name",
    scalaVersion := "2.12.7",
  )

のような感じになっていて理解ができない。改めて見てみるとなんとなく分からなくはないが入門向けのものと本番のものとで違いがでか過ぎて困る。

とか思ってたら別の調べ物をしてたときにsbtのサイトを見つけた。あったのか・・・

sbt Reference Manual — sbt Reference Manual

この中のビルド定義のページを読んだら何がどうなっているかおおむね理解できた。

:= の意味も分からなかったのだがこれはメソッドだったんだな。

変更後

当初のbuild.sbtがイケてなかったので書き直した

scalaVersion := "2.12.6"

version := "1.0"

lazy val commonSettings = Seq(
  scalacOptions ++= Seq("-deprecation", "-feature", "-unchecked", "-Xlint"),
  libraryDependencies ++= Seq(
    "org.scalatest" %% "scalatest" % "3.0.5" % "test",
    "org.mockito" % "mockito-core" % "2.13.0" % "test",
    "com.typesafe.scala-logging" %% "scala-logging" % "3.9.2",
    "ch.qos.logback" % "logback-classic" % "1.2.3",
  ),
)

lazy val domain = (project in file("domain"))
  .settings(
    commonSettings,
    name := "queue_domain",
  )

lazy val provider = (project in file("provider"))
  .settings(
    commonSettings,
    name := "provider",
    libraryDependencies ++= Seq(
      "com.typesafe.akka" %% "akka-http" % "10.1.8",
      "com.typesafe.akka" %% "akka-stream" % "2.5.19",
      "com.typesafe.akka" %% "akka-http-spray-json" % "10.1.8",
    ),
  )
  .dependsOn(domain)

lazy val consumer = (project in file("consumer"))
  .settings(
    commonSettings,
    name := "consumer",
  )
  .dependsOn(domain)

こんな感じにした。 LogとかTestは共通なのでcommonSettingsに、WebサーバはProviderでしか使わないのでAkkaHTTPをProvider配下に、Queueクラスとかドメイン層は共通で使われるので別のプロジェクトにしてproviderとconsumerから呼び出すようにした。 なるほど、ようやく社内のリポジトリのbuild.sbtが読めそう。build.sbtを見れば大体そのプロジェクトがどういう構成になってるか分かるよ、と言われたのが少し理解できた気がする。あーだいぶスッキリした。

packageとディレクト

この変更をするにあたり、ディレクトリ構成も変更した。 もともとは

├── src
│   └── main
│       ├── resources
│       └── scala
│           └── com
│               └── shmrkm
│                   └── queue
│                       ├── client
│                       ├── consumer
│                       └── provider

こんな形にしていたのだけど、consumerとproviderは別のサブプロジェクトになるはずなので明確に分けるようにした。変更後は↓のようになった。

consumer
├── src
│   └── main
│       ├── resources
│       └── scala
│           └── com
│               └── shmrkm
│                   └── queue
│                       └── consumer

domain
├── src
│   └── main
│       ├── resources
│       └── scala
│           └── com
│               └── shmrkm
│                   └── queue
│                       └── domain

provider
├── src
│   ├── main
│   │   ├── resources
│   │   └── scala
│   │       └── com
│   │           └── shmrkm
│   │               └── queue
│   │                   └── provider

Provider用のMainを書いてるけどConsumer用のMainを書きたくなったらどうすんだろ、と思ってたけどこうすれば良かったんだな。