Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Should Repository be parameterised (object, id type)? #45

Open
lloydmeta opened this issue Dec 18, 2018 · 3 comments
Open

Should Repository be parameterised (object, id type)? #45

lloydmeta opened this issue Dec 18, 2018 · 3 comments

Comments

@lloydmeta
Copy link

Currently making my way through the book in detail (awesome btw), and I realised that in Chapter 5, AccountService is parameterised on Account, Amount, and Balance, which is awesome, but AccountRepository on which it depends is not; I was curious if it should be ?

trait AccountService[Account, Amount, Balance] {
type AccountOperation[A] = Kleisli[Valid, AccountRepository, A]
def open(no: String, name: String, rate: Option[BigDecimal], openingDate: Option[Date],
accountType: AccountType): AccountOperation[Account]
def close(no: String, closeDate: Option[Date]): AccountOperation[Account]
def debit(no: String, amount: Amount): AccountOperation[Account]
def credit(no: String, amount: Amount): AccountOperation[Account]
def balance(no: String): AccountOperation[Balance]
def transfer(from: String, to: String, amount: Amount): AccountOperation[(Account, Account)] = for {
a <- debit(from, amount)
b <- credit(to, amount)
} yield ((a, b))
}

trait AccountRepository {
def query(no: String): \/[NonEmptyList[String], Option[Account]]
def store(a: Account): \/[NonEmptyList[String], Account]
def balance(no: String): \/[NonEmptyList[String], Balance] = query(no) match {
case \/-(Some(a)) => a.balance.right
case \/-(None) => NonEmptyList(s"No account exists with no $no").left[Balance]
case a @ -\/(_) => a
}
def query(openedOn: Date): \/[NonEmptyList[String], Seq[Account]]
def all: \/[NonEmptyList[String], Seq[Account]]
}

In effect, doesn't this mean that AccountService is coupled to the concrete models due to

type AccountOperation[A] = Kleisli[Valid, AccountRepository, A]

?

@debasishg
Copy link
Owner

Thanks for your comments ..

Regarding AccountRepository, it's not an implementation, it's a trait for which u can have multiple implementations. And the trait is injected into AccountService through a Kleisli, which is a ReaderT. So the repository is injected into the service from the environment - hence no coupling. And this is done at the end of the world when u implement the Application https://github.com/debasishg/frdomain/blob/master/src/main/scala/frdomain/ch5/domain/app/app.scala#L57) ..

@lloydmeta
Copy link
Author

lloydmeta commented Dec 18, 2018

Right, but the algebra of the AccountRepository is hard-coded to use the concrete Account model

That in turn shows up in the algebra of the AccountService through the Kleisli

accountType: AccountType): AccountOperation[Account]

In other words, AccountService#open for instance is basically:

trait AccountService[Account /* this is parameterized, which is good */] { 
  def open(
    no: String,
    name: String,
    rate: Option[BigDecimal],
    openingDate: Option[Date],
    accountType: AccountType
  )(repository: { def store(a: models.Account /* here we leak the concrete Account model */): \/[NonEmptyList[String], Account] }): Valid[Account]
}

EDIT: My question essentially boils down to: if we're going through the trouble of parameterising AcocuntService on Account type, wouldn't it make sense to do so for the AccountRepository as well? As it is, it seems clear that the only kind of Account that could be used with AccountService is the concrete model.Account, same for Amount.

@debasishg
Copy link
Owner

ah .. I get what you say. You are correct! It would certainly be better to parameterize the algebra of repository with the domain entities as type parameters.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants