# 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が発生する|