1

Hi I have the following Scala code with cats library

results = patrons.map(p => {
  (verifyCardId(p.cardId), verifyAddress(p.address)).map2(
  (maybeValidCard, maybeValidAddress) => {
    val result = for {
      idCheck <- maybeValidCard
      addressCheck <- maybeValidAddress
    } yield CheckResult(p.name, idCheck, addressCheck)
  }
})

where verifyCardId and verifyAddress is an external API call returning a Future which are somehow very expensive and time consuming.

The question is how do I do the following:

  • If one of the patron does not have a card, the code should be able to skip checking the card must still check patron's address
  • If the patron has both then, the code should check the card and the address

How can I improve the existing code? Thanks heaps

Edit: Add more information about the preference to skip one of the expensive API calls

Don Djoe
  • 705
  • 1
  • 10
  • 21

1 Answers1

1
  • If result of address verification doesn't depend on result of card verification then untie them (flatMap binds monads).
  • Model CheckResult should be adjusted to case of missing card.

extended sample

    case class Patron(name: String, cardId: String, address: String)
    case class CheckResult(name: String, idCheck: Option[Boolean], addressCheck: Boolean)
    def verifyCardId(cardId: String) = Future{
      Thread.sleep(5000)
      Some(true)
    }
    def verifyAddress(address: String) = Future{
      Thread.sleep(5000)
      Some(true)
    }

    val patrons = List(Patron("p_name", "1234", "Somewhere St. 42"))

    val start = LocalDateTime.now()
    val results = patrons.map(p => {
      (verifyCardId(p.cardId), verifyAddress(p.address)).map2(
        (maybeValidCard, maybeValidAddress) => {
          for {
            addressCheck <- maybeValidAddress
          } yield CheckResult(p.name, maybeValidCard, addressCheck)
        })
    })
    val headResult = Await.result(results.head, Duration.Inf)
    val end = LocalDateTime.now()
    val duration = ChronoUnit.SECONDS.between(start, end)

short output

    patrons: List[Patron] = List(Patron(p_name,1234,Somewhere St. 42))
    headResult: Option[CheckResult] = Some(CheckResult(p_name,Some(true),true))
    duration: Long = 5
Zernike
  • 1,758
  • 1
  • 16
  • 26
  • Thanks for the answer but I guess I didn't explain my intention well enough. I have updated the question. True that both verifications do not depends on each other. But it is also preferred if they both can be called at the same time to save time. My intention is to skip one of them given a specific scenario (i.e. no card) – Don Djoe Jun 02 '17 at 07:32
  • I updated answer. Only results of calls are untied. Futures are computed asynchronous and in parallel way. – Zernike Jun 02 '17 at 08:57