Repository
RepositoryとはEntityの永続化を隠蔽するためのモジュールです。
なぜRepositoryが必要なのか?
Repositoryを使用することで、ビジネスロジックを記述する際に、どのDBを使っていて、どのような問い合わせを行ってデータを取得したり、保存するのかを意識する必要がなくなります。
また、DBの種類を変更する際に、ビジネスロジックを変更する必要がなくなります。。
Repositoryが役に立った実例
Flutterを用いたモバイルアプリ開発の際に、当初はFirestoreのSDKを用いてクライアントから直接Firestoreに問い合わせを行っていました。
しかし、セキュリティー的にクライアントから直接Firestoreに問い合わせを行ってはいけないことが分かり、Cloud Functionsを経由してFirestoreにアクセスする必要がでてきました。
データアクセスはRepositoryで行うようにしていたため、Repositoryを書き換えるだけで、ビジネスロジックを変更する必要がなく、開発を進めることが可能となりました。
Repositoryの実装例
Dart言語では、次のようなインターフェースでRepositoryを定義することが多いです。
save, delete, findByIdなどは、どのDBでも同じインターフェースで定義することができるため、ビジネスロジックを記述する際に、どのDBを使用しているのかを意識する必要がなくなります。
abstract class UserRepository {
Future<User?> findById(UserId id);
Future<User?> findByEmail(String email);
Future<User> save(User user);
Future<void> delete(UserId id);
}RepositoryはEntityが存在してるということを意識せずに、ビジネスロジックを記述できたほうがよいため、基本的にはcreate, updateなどを個別に定義することはしないです。
アンチパターン
Repositoryにビジネスロジックを記述することは避けるべきです。
たとえば、ユーザーのログイン日時を更新する際に、以下のようなメソッドをRepositoryに定義するようなことは避けるべきです。
abstract class UserRepository {
Future<User?> updateLastLoginAt(UserId id);
}ログイン日時の更新は、永続化とは無関係の操作であるため、saveメソッドを利用して、repo.save(user.updateLatestLoginAt())のようにビジネスロジック側で計算して、永続化を行うことが推奨されます。