Scalaで最強のRepositoryパターンを実装する ~①howとwhatの分離~

# はじめに
ScalaのWebアプリケーションを作る上で最強のRepositoryパターンを考察していきます。
間違えていることはぜひご指摘いただけると幸いです。

本記事で触れるような実装はだいたい以下のリポジトリで公開しています。
https://github.com/YuitoSato/user-manager

また、①があると②もあるということで連載形式で記事を公開していきます

2018/4/29現在の連載記事一覧です↓
[①の記事 ~howとwhatの分離~](https://qiita.com/YuitoSato/items/730add80659718c79bd6)
[②の記事 ~トランザクションモナド~](https://qiita.com/YuitoSato/items/d81b76e1757d45afae0f)
[③の記事 ~ScalikeJDBCによる実装~](https://qiita.com/YuitoSato/items/726e9fbc96bc3c561034)
[④の記事 ~テストコード~](https://qiita.com/YuitoSato/items/fe73430befe2505813be)

# 対象者
- Scalaがだいたい書ける
- ScalaでWebアプリ作れる
- モナ○が少しわかる
- Repositoryパターンに興味がある

## Repositoryパターンとは（復習）
Repositoryパターンは**ビジネスロジックとデータアクセスロジックを分離するためのパターン**を指します。
[詳しくはこちら](http://blog.karamem0.jp/entry/2016/11/01/190000)

ビジネスロジックとデータアクセスロジックを分離することで、ビジネスロジックのテストが簡単になったり、可読性が向上します。

# 環境
- Scala 2.12
- Google Guice 4.1.0
- ScalikeJDBC 3.2.1
- Scalatest 3.0.1

# howとwhatの分離
では最強とはなんなのか？

筆者が考える最強とはhowとwhatが分離されているRepositoryです。

**どう実現するか**よりも**何をするか**のほうが大事です。
どうやってユーザーの情報を取得するかよりも、どのユーザーの情報を取得するかのほうが圧倒的に大事です。

そのため、**どう実現するかは隠蔽します。**
具体的なデータの取得方法や更新方法は、アプリケーション層や、DDDでいうところのドメイン層から見えないようにするべきなのです。

アプリケーション層やドメイン層には何をしているのかのwhatの部分だけ見せ、純粋なビジネスロジックに集中できるようにします。

具体的にどうするのかというとインターフェースを作成して、内部の具体的なアクセスロジックは隠蔽します。
実装はDIによって管理します。

```scala

trait UserRepository {

  // howは隠蔽し、whatだけ公開する
  def find(id: Long): Option[User]

}
```

# なぜhowを隠蔽するのか
上の例にある通り、ここでいう隠蔽とはtraitによるインターフェースを用意し実装クラスをDIすることで、アプリケーション層やドメイン層からhowを見えなくするということを指します。

DIを行いhowを隠蔽する利点は、

**①テストをしやすくする**
**②howを差し替え可能にする**

一つ目は**テストがしやすくなる**という利点です。というかこれが主だと思います。
howを隠蔽しないと基本的にテストがしにくくなります。

SlickのDBIOのモックを作るのは骨が折れますし、だれもFutureのインスタンスをawaitしたくないです。
インターフェースであれば、モックを注入することは容易になり、アプリケーション層やドメイン層のテスタビリティが向上します。


二つ目は**howが差し替え可能になる**という利点です。OR Mapperを差し替えることはあまりないかもですが、疎結合になることで差し替えコストが向上します。
今までMySqlだったけど、NoSqlで一部差し替えたいというケースでも対応できます。



# Repositoryパターンにおけるhow
Repositoryパターンにおけるhowは3つあります。
それは **①どのデータベースから**、**②どのツールを使って**、**③どうスレッドを管理するか**です。

**一つ目はデータベースです。**
データベースとは「検索や蓄積が容易にできるよう整理された情報の集まり」を指します。
RDBだけではないです。MySQL、NoSQL、Memcachedなどなどいろいろなものを指します。

**二つ目はツールです。**
ここでは特にO/Rマッパーを指します。
MySQLならScalikejdbc、Hibernateなど、Memcachedならshadeなどです。

**三つ目はスレッド管理です。**
ここではノンブロッキングかブロッキングかを指します。
これはORマッパーによるところが多いですが、こちらのスレッド管理も隠蔽していきます。


**howが隠蔽できていないパターン**

```scala 
class UserRepository {

  // SlickのDBIOを返しているのでSlickというORマッパーが隠蔽できていない
  // Slickを使用しているので MySQLやノンブロッキングというhowが隠蔽できていない
  def find(id: Long): DBIO[Option[User]] = {
    中略
  }

  // ScalikejdbcのDBSessionが隠蔽できていない
  def find(id: Long)(dbSession: DBSession): Option[User] = {
    中略
  }

}
```

# 最終形態
先に本記事の最終形態をお見せします。

ここまでの話からhowが隠蔽できているRepositoryなら良いということになりますね。

```scala

trait UserRepository {

  def find(id: Long): Option[User]

}
```

上に挙げた例の通り本当はこうしたいですね。
しかしOR Mapperによっては、返す値が変わったり、引数に特別なものを取らないといけないケースが出てきます。
上の例のようなインターフェースを公開するだけだと難しそうです。


そのため


```scala

trait Transaction[A]

trait UserRepository {

  def find(id: Long): Transaction[Option[User]]

}
```

**返り値にも抽象化した型であるTransactionクラスを用意します。**
これで自由度が上がりました。

SlickやShadeを使う際はこのUserRepositoryとTransactionクラスを実装していけばできそうですね。

次の②の記事では、もう少しこのTransactionクラスの性質を掘り下げていきます。

[②の記事:トランザクションモナド編](https://qiita.com/YuitoSato/items/d81b76e1757d45afae0f)

では！