Upgrade to Pro — share decks privately, control downloads, hide ads and more …

運用を続けていくための Scala の書き方 / scala.rookies#1

kenchan0130
November 29, 2018

運用を続けていくための Scala の書き方 / scala.rookies#1

scala.rookies#1 (https://scala-rookies.connpass.com/event/105904/) で発表した資料です

kenchan0130

November 29, 2018
Tweet

More Decks by kenchan0130

Other Decks in Technology

Transcript

  1. '0-*0דך4DBMB 4DBMB੡ͷϚΠΫϩαʔϏε        

      䎃剢Ĕ晛ٔٔ٦أ  䎃剢劤ٔٔ٦أ   
  2. def hoge(): EitherT[Future, FugaException, Unit] def bar(): OptionT[Future, Entity] ٌشسزٓٝأؿؓ٦و٦׾ז׷ץֻ㢩鿇ח⳿ׁזְ

    def hoge(): Future[Either[FugaException, Unit]] def bar(): Future[Option[Entity]] ྑ͘ͳ͍ͱߟ͍͑ͯΔॻ͖ํ ྑ͍ͱߟ͍͑ͯΔॻ͖ํ
  3. // val ctx: DataBaseContext // val userId: UserId ctx.transaction {

    val eitherT = for { repo1Entity <- OptionT (repository1.findEntityBy(userId)).toRight(new RuntimeException("Error")) _ <- EitherT.right(repository2.create(repo1Entity)) } yield () eitherT.run.flatMap { case -\/(_) => Future.exception((new RuntimeException("Error"))) case \/-(a) => Future.value(\/-(a)) } } %#זוךزٓٝؠؙءّٝⳢ椚דכ琎噰涸ח⢽㢩׾ちֻ ྑ͘ͳ͍ͱߟ͍͑ͯΔॻ͖ํ
  4. implicit class OptionToFuture[A](option: Option[A]) { def toFuture(whenNone: => Throwable): Future[A]

    = option match { case Some(a) => Future.value(a) case None => Future.exception(whenNone) } } ctx.transaction { for { repo1EntityOpt <- repository1.findEntityBy(userId) repo1Entity <- repo1EntityOpt.toFuture(new RuntimeException("Error")) _ <- repository2.create(repo1Entity) } yield () } %#זוךزٓٝؠؙءّٝⳢ椚דכ琎噰涸ח⢽㢩׾ちֻ ྑ͍ͱߟ͍͑ͯΔॻ͖ํ
  5. sealed abstract class DbError(val msg: String, e: Throwable) extends RuntimeException(msg,

    e) case class ConnctionError(cause: Throwable) extends DbException("Connection Error", cause) case class TimeoutError(cause: Throwable) extends DbException("Timeout Error", cause) case class TimeoutError(cause: Throwable) extends DbException("Duplicated Entry Error", cause) @Singleton class ExecuteImpl { def execute(): Future[SchemeModel] = { // It is possible the execute method raise some exceptions of DbCtxError. ctx.execute().map(Right.apply).rescue { case e: DbCtxCancelConnection => Left(ConnctionError(e)) case e: DbCtxTimeout => Left(TimeoutError(e)) case e: DbCtxDuplicatedEntry => Left(TimeoutError(e)) } } } ⶰ⡲欽׾搀椚ח㘗ד邌植׃זְ ྑ͘ͳ͍ͱߟ͍͑ͯΔॻ͖ํ
  6. ⶰ⡲欽׾搀椚ח㘗ד邌植׃זְ @Singleton class ExecuteImpl { def execute(): Future[SchemeModel] = ctx.execute()

    } @Singleton class ExecuteApiController @Inject()(executeImpl: ExecuteImpl) { // It is possible the execute method raise some exceptions of DbCtxError. def run(): Future[Unit] = executeImpl.execute().map(_ => ()) } @Singleton class Endpoint @Inject()(controller: ExecuteApiController) { override val executeApi(): Future[Unit] = { controller.run().rescue { case e: DbCtxError => Future.exception(e) } } } ྑ͍ͱߟ͍͑ͯΔॻ͖ํ
  7. // Auto Generated Code case class User(id: Int, name: String)

    case class UserDetail(phone: String, birthdate: String, sex: Int) // Auto Generated Code @Singleton class UserInternalApiClient { // Auto Generated Code def getUser(): Future[User] = { /** compiled code **/ } def getUserDetail(userId: Int): Future[UserDetail] = { /** compiled code **/ } } @Singleton class ReturningUserDetailUserCase @Inject()(client: UserInternalApiClient) { def run(): Future[UserDetail] = { for { user <- clinet.getUser() userDetail <- client.getUserDetail(user.id) } yield userDetail } } %#װ"1*ؙٓ؎،ٝزך鵤⽱⦼ך㘗׾׉ךתת⢪ְ㔐ׁזְ ྑ͘ͳ͍ͱߟ͍͑ͯΔॻ͖ํ
  8. // Auto Generated Code case class User(id: Int, name: String)

    case class UserDetail(birthdate: String, sex: Int) // Auto Generated Code @Singleton class UserInternalApiClient { // Auto Generated Code def getUser(): Future[User] = { /** compiled code **/ } def getUserDetail(userId: Int): Future[UserDetail] = { /** compiled code **/ } } %#װ"1*ؙٓ؎،ٝزך鵤⽱⦼ך㘗׾׉ךתת⢪ְ㔐ׁזְ ྑ͍ͱߟ͍͑ͯΔॻ͖ํ
  9. case class MyUser(id: UserId, name: Name, birthdate: Birthdate, sex: Sex)

    @Singleton class UserInternalApiClientAntiCorruption @Inject()(clinet: UserInternalApiClient) { def getUser(): Future[MyUser] = for { user <- clinet.getUser() detail <- client.getUserDetail(Random.shuffle(idList).head) } yield MyUser( UserId(user.id), Name(user.name), Birthdate(detail.birthdate), Sex(detail.sex) ) } @Singleton class ReturningUserDetailUserCase @Inject()(antiCorruption: UserInternalApiClientAntiCorruption) { def run(): Future[MyUser] = { antiCorruption.getUser() } } %#װ"1*ؙٓ؎،ٝزך鵤⽱⦼ך㘗׾׉ךתת⢪ְ㔐ׁזְ ྑ͍ͱߟ͍͑ͯΔॻ͖ํ