# UserId などの型はどうするべきか ## 1. primitive 型をそのまま使う ```scala case class Person(id: Long, name: String, organizationId: Long) object Person { def groupByOrg: Map[Long, Seq[Person]] = ... } ``` ### メリット 1. wrap/unwrapが存在しない 1. Boxing/Unboxingが発生しない 1. 大抵のDBライブラリやJSONライブラリなどでそのまま扱える 1. 定義が楽 ### デメリット 1. 型安全でない 1. シグネチャだけで意味が取れない ## 2. type alias を使う ```scala package object models { type PersonId = Long type PersonName = String type OrganizationId = Long } case class Person(id: PersonId, name: PersonName, organizationId: OrganizationId) object Person { def groupByOrg: Map[OrganizationId, Seq[Person]] = ... } ``` ### メリット 1. wrap/unwrapが存在しない 1. Boxing/Unboxingが発生しない 1. 大抵のDBライブラリやJSONライブラリなどでそのまま扱える 1. シグネチャだけで意味がわかりやすい ### デメリット 1. 型安全でない 1. 定義が手間 ## 3. 専用の値クラスを作る ```scala case class PersonId(value: Long) extends AnyVal case class PersonName(value: String) extends AnyVal case class OrganizationId(value: Long) extends AnyVal case class Person(id: PersonId, name: PersonName, organizationId: OrganizationId) object Person { def groupByOrg: Map[OrganizationId, Seq[Person]] = ... } ``` ### メリット 1. 型安全 1. シグネチャだけで意味がわかりやすい 1. 特定のケースを除いてwrap/unwrap時にオーバーヘッドが存在しない 1. Boxing/Unboxingが発生しない 1. メソッドが定義しやすい ### デメリット 1. 定義が手間 1. DBライブラリやJSONライブラリなどで変換ロジックを書く必要がある 1. 特定のケースでオーバーヘッドが存在する ## 4. TaggedType を使う ```scala import scalaz._ import scalaz.Tag._ package object models { type Id = Long type Name = String } case class Person(id: Id @@ Person, name: Name @@ Person, organizationId: Id @@ Organization) object Person { def groupByOrg: Map[Id @@ Organization, Seq[Person]] = ... val tagOf: TagOf[Person] = Tag.of[Person] } ``` ### メリット 1. 型安全 1. シグネチャだけで意味がわかりやすい 1. wrap/unwrap時にオーバーヘッドが存在しない 1. 定義が楽 ### デメリット 1. DBライブラリやJSONライブラリなどで変換ロジックを書く必要がある 1. Boxing/Unboxingが発生する ## まとめ | |メリット |デメリット | |------------|-------------------|-----------------------| |primitive 型|* wrap/unwrapが存在しない
* Boxing/Unboxingが発生しない
* 大抵のDBライブラリやJSONライブラリなどでそのまま扱える
* 定義が楽|
* 型安全でない
* シグネチャだけで意味が取れない| |type alias |* wrap/unwrapが存在しない
* Boxing/Unboxingが発生しない
* 大抵のDBライブラリやJSONライブラリなどでそのまま扱える
* シグネチャだけで意味がわかりやすい|* 型安全でない
* 定義が手間| |値クラス |* 型安全
* シグネチャだけで意味がわかりやすい
* 特定のケースを除いてwrap/unwrap時にオーバーヘッドが存在しない
* Boxing/Unboxingが発生しない
* メソッドが定義しやすい|* 定義が手間
* DBライブラリやJSONライブラリなどで変換ロジックを書く必要がある
* 特定のケースでオーバーヘッドが存在する| |TaggedType |* 型安全
* シグネチャだけで意味がわかりやすい
* wrap/unwrap時にオーバーヘッドが存在しない
* 定義が楽|* DBライブラリやJSONライブラリなどで変換ロジックを書く必要がある
* Boxing/Unboxingが発生する|