Tagless Final Style Repository의 Highr Kind가 다른 경우 Use Case를 작성하는 방법
11442 단어 TaglessFinalScala
주로, 다음의 Slide나, GitHub를 참조했습니다. Aoyama, 감사합니다
내가 작성한 코드는 htps : // 기주 b. 코 m / 요시 요시 후지이 / s ぁ- g ぇ s s 푹신한 l-에 mp ぇ입니다.
리포지토리
Tagless Final Style인 Repository는, 여러가지 곳에서 눈에 접할 수 있다고 생각하기 때문에, 여기에서는 반대로 사쿠로 기재해 둡니다.
trait UserRepository[F[_]] {
def store(user: User): F[UserId]
}
trait AccountRepository[F[_]] {
def store(account: Account): F[AccountId]
}
그래서, 이번 곤란한 짱은, 이, 각각의 Repository를, 같은 Use Case로 취급하고 싶지만, 각각, RDB와 Redis라든지 다른 영속화를 한다고 해도 경우에, F[_]가 다르기 때문에, 곤란해 버린다 라고 이야기.
그래도, 역시, Use Case에 자세한 것은 반입하고 싶지 않아요. 방침만으로 쓰고 싶지 않은데 대책했다.
Use Case
정책만으로 쓰는 Use Case는 이하.
import cats._
import cats.implicits._
class AccountCreateUseCase[F[_]: Monad: UserRepository: AccountRepository] {
def execute(name: String, email: String): F[String] = {
for {
userId <- implicitly[UserRepository[F]].store(User.create(name))
accountId <- implicitly[AccountRepository[F]].store(Account.create(email))
} yield s"$userId-$accountId"
}
}
여기에서는, User나 Account의 생성 로직이라든지, 그러한 도메인의 근처라든지는 적절히 생략하고 있습니다.
포인트로서는
class AccountCreateUseCase[F[_]: Monad: UserRepository: AccountRepository] {
그런 다음,
implicitly[UserRepository[F]]
해야합니다.
여기서 UserRepository와 AccountRepository를 형식 클래스로 취급합니다.
그렇지만, 여기는, 실은, 잘 잘 모르고, 자세한 분에게 꼭 교수해 주셨으면 한다.
어쨌든, 이렇게 쓸 필요가 있고, 또한, trait에서는 안 되고 class로 쓸 필요가 있는 것 같다.
조금 구구한 느낌으로, htps : // bg. s 또는 c. 이오/2017/04/19/tyぺcぁせ s-인-s? HTML 을 배독하고 있으면, 아무래도,
class AccountCreateUseCase[F[_]: Monad](implicit ur: UserRepository, ac: AccountRepository)
라고 쓰는 것과 같은 느낌 같네요.
그 후,
import cats.implicits._
를 해 두지 않으면, for식에 전개할 수 없기 때문에 주의가 필요.
Adapters
상세한 곳.
UserRepository나 AccountRepository의 구현에 해당하지만, 여기서 각각의 F[_]가 다르다는 것을 다음 표현으로 보았다.
type SpecialF[A] = ReaderT[Future, (DBConnection, RedisConnection), A]
단순한 경우라면,
type UserF[A] = ReaderT[Future, DBConnection, A]
type AccountF[A] = ReaderT[Future, RedisConnection, A]
하지만, 이것을하면 F [_]가 다르므로 이것을 type 곳에서 하나로 긁어 넣는 것으로 구현 타이밍에서 필요한 Connection을 선택하고 취급한다는 역기술 로 해 보았다.
UserRepository의 구현만 나타내면 다음과 같은 느낌이 된다.
implicit def userRepository(implicit ec: ExecutionContext): UserRepository[SpecialF] =
new UserRepository[SpecialF] {
override def store(user: User): SpecialF[UserId] =
ReaderT {
case (db, _) =>
Future(user.id)
}
}
Main
Main은
implicit val ec: ExecutionContext = ExecutionContext.global
val useCase = new AccountCreateUseCase[SpecialF]
val result = useCase
.execute("name", "[email protected]")
.run((new DBConnection, new RedisConnection))
assert(Await.result(result, 1.second) === "UserId(1)-AccountId(2)")
같은 느낌이 된다.
run에, tuple로, 각각의 Connection를 건네주는 느낌으로, 구현측에서 필요한 것을 취한다.
요약
일단, 이것으로 움직였지만, 아직 미묘한 곳이 있다.
RDB와, Redis를 같은 Project에 포함하고 있거나, 상호 참조하고 있는 느낌이기 때문에, 거기를 분리하고 싶어지면 할 수 없을 것 같거나.
Adapters를 구현할 때 어떤 물건이 필요한지 판단해 가는데 Use Case가 복잡하다면 꽤 거대한 Type이 생길 것 같거나…
그렇다고는 해도, 그 근처는, 상세하고, Clean Architecture적으로는, 결정을 늦추고 싶은 내용이기도 하기 때문에, 그 근처를 트레이드 해 나가는가 되어 느낌입니다.
아직 시행착오 도중입니다만, 여기까지 알게 된 내용으로, 정리해 둡니다.
이상입니다.
Reference
이 문제에 관하여(Tagless Final Style Repository의 Highr Kind가 다른 경우 Use Case를 작성하는 방법), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://qiita.com/yoshiyoshifujii/items/eddc174a19d0a4cc51ce
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
trait UserRepository[F[_]] {
def store(user: User): F[UserId]
}
trait AccountRepository[F[_]] {
def store(account: Account): F[AccountId]
}
정책만으로 쓰는 Use Case는 이하.
import cats._
import cats.implicits._
class AccountCreateUseCase[F[_]: Monad: UserRepository: AccountRepository] {
def execute(name: String, email: String): F[String] = {
for {
userId <- implicitly[UserRepository[F]].store(User.create(name))
accountId <- implicitly[AccountRepository[F]].store(Account.create(email))
} yield s"$userId-$accountId"
}
}
여기에서는, User나 Account의 생성 로직이라든지, 그러한 도메인의 근처라든지는 적절히 생략하고 있습니다.
포인트로서는
class AccountCreateUseCase[F[_]: Monad: UserRepository: AccountRepository] {
그런 다음,
implicitly[UserRepository[F]]
해야합니다.
여기서 UserRepository와 AccountRepository를 형식 클래스로 취급합니다.
그렇지만, 여기는, 실은, 잘 잘 모르고, 자세한 분에게 꼭 교수해 주셨으면 한다.
어쨌든, 이렇게 쓸 필요가 있고, 또한, trait에서는 안 되고 class로 쓸 필요가 있는 것 같다.
조금 구구한 느낌으로, htps : // bg. s 또는 c. 이오/2017/04/19/tyぺcぁせ s-인-s? HTML 을 배독하고 있으면, 아무래도,
class AccountCreateUseCase[F[_]: Monad](implicit ur: UserRepository, ac: AccountRepository)
라고 쓰는 것과 같은 느낌 같네요.
그 후,
import cats.implicits._
를 해 두지 않으면, for식에 전개할 수 없기 때문에 주의가 필요.
Adapters
상세한 곳.
UserRepository나 AccountRepository의 구현에 해당하지만, 여기서 각각의 F[_]가 다르다는 것을 다음 표현으로 보았다.
type SpecialF[A] = ReaderT[Future, (DBConnection, RedisConnection), A]
단순한 경우라면,
type UserF[A] = ReaderT[Future, DBConnection, A]
type AccountF[A] = ReaderT[Future, RedisConnection, A]
하지만, 이것을하면 F [_]가 다르므로 이것을 type 곳에서 하나로 긁어 넣는 것으로 구현 타이밍에서 필요한 Connection을 선택하고 취급한다는 역기술 로 해 보았다.
UserRepository의 구현만 나타내면 다음과 같은 느낌이 된다.
implicit def userRepository(implicit ec: ExecutionContext): UserRepository[SpecialF] =
new UserRepository[SpecialF] {
override def store(user: User): SpecialF[UserId] =
ReaderT {
case (db, _) =>
Future(user.id)
}
}
Main
Main은
implicit val ec: ExecutionContext = ExecutionContext.global
val useCase = new AccountCreateUseCase[SpecialF]
val result = useCase
.execute("name", "[email protected]")
.run((new DBConnection, new RedisConnection))
assert(Await.result(result, 1.second) === "UserId(1)-AccountId(2)")
같은 느낌이 된다.
run에, tuple로, 각각의 Connection를 건네주는 느낌으로, 구현측에서 필요한 것을 취한다.
요약
일단, 이것으로 움직였지만, 아직 미묘한 곳이 있다.
RDB와, Redis를 같은 Project에 포함하고 있거나, 상호 참조하고 있는 느낌이기 때문에, 거기를 분리하고 싶어지면 할 수 없을 것 같거나.
Adapters를 구현할 때 어떤 물건이 필요한지 판단해 가는데 Use Case가 복잡하다면 꽤 거대한 Type이 생길 것 같거나…
그렇다고는 해도, 그 근처는, 상세하고, Clean Architecture적으로는, 결정을 늦추고 싶은 내용이기도 하기 때문에, 그 근처를 트레이드 해 나가는가 되어 느낌입니다.
아직 시행착오 도중입니다만, 여기까지 알게 된 내용으로, 정리해 둡니다.
이상입니다.
Reference
이 문제에 관하여(Tagless Final Style Repository의 Highr Kind가 다른 경우 Use Case를 작성하는 방법), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://qiita.com/yoshiyoshifujii/items/eddc174a19d0a4cc51ce
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
type SpecialF[A] = ReaderT[Future, (DBConnection, RedisConnection), A]
type UserF[A] = ReaderT[Future, DBConnection, A]
type AccountF[A] = ReaderT[Future, RedisConnection, A]
implicit def userRepository(implicit ec: ExecutionContext): UserRepository[SpecialF] =
new UserRepository[SpecialF] {
override def store(user: User): SpecialF[UserId] =
ReaderT {
case (db, _) =>
Future(user.id)
}
}
Main은
implicit val ec: ExecutionContext = ExecutionContext.global
val useCase = new AccountCreateUseCase[SpecialF]
val result = useCase
.execute("name", "[email protected]")
.run((new DBConnection, new RedisConnection))
assert(Await.result(result, 1.second) === "UserId(1)-AccountId(2)")
같은 느낌이 된다.
run에, tuple로, 각각의 Connection를 건네주는 느낌으로, 구현측에서 필요한 것을 취한다.
요약
일단, 이것으로 움직였지만, 아직 미묘한 곳이 있다.
RDB와, Redis를 같은 Project에 포함하고 있거나, 상호 참조하고 있는 느낌이기 때문에, 거기를 분리하고 싶어지면 할 수 없을 것 같거나.
Adapters를 구현할 때 어떤 물건이 필요한지 판단해 가는데 Use Case가 복잡하다면 꽤 거대한 Type이 생길 것 같거나…
그렇다고는 해도, 그 근처는, 상세하고, Clean Architecture적으로는, 결정을 늦추고 싶은 내용이기도 하기 때문에, 그 근처를 트레이드 해 나가는가 되어 느낌입니다.
아직 시행착오 도중입니다만, 여기까지 알게 된 내용으로, 정리해 둡니다.
이상입니다.
Reference
이 문제에 관하여(Tagless Final Style Repository의 Highr Kind가 다른 경우 Use Case를 작성하는 방법), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://qiita.com/yoshiyoshifujii/items/eddc174a19d0a4cc51ce
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
Reference
이 문제에 관하여(Tagless Final Style Repository의 Highr Kind가 다른 경우 Use Case를 작성하는 방법), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/yoshiyoshifujii/items/eddc174a19d0a4cc51ce텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)