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

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

8fd1ae6548d5ab14139c8d8032b76ee1?s=47 kenchan0130
November 29, 2018

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

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

8fd1ae6548d5ab14139c8d8032b76ee1?s=128

kenchan0130

November 29, 2018
Tweet

Transcript

  1. 麊欽׾竲ֽגְֻ׋׭ך 4DBMBך剅ֹ倯 2018/11/29ɹscala.rookies#1

  2. 㣐銮姻䛾 (Tadayuki Onishi) Software Engineer Twitter: @kenchan0130 Blog: kenchan0130.github.io 荈䊹稱➜

  3.  痥♧珏ꆃ輐㉀ㅷ《䒷噟罏䎃։  䎃剢ח鏣甧  䖞噟㆞秈せ䎃剢植㖈  ؿؓٔؔIUUQTGPMJPTFDDPNך؟٦ؽأ׾䲿⣘

  4. None
  5. '0-*0דך4DBMB  5ISJGU"1*4FSWFS"QQMJDBUJPO  )5513&45"1*4FSWFS "QQMJDBUJPO  #BUDI"QQMJDBUJPO  1VC4VC欽%FNPO"QQMJDBUJPO

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

      䎃剢Ĕ晛ٔٔ٦أ  䎃剢劤ٔٔ٦أ   
  7. '0-*0דך4DBMB ࣾ಺ϥΠϒϥϦ͸ 20 Ҏ্

  8. '0-*0דך4DBMB 圫ղז044ٓ؎ـٓٔח״׏ג 佄ִ׵׸גְ׷

  9. '0-*0ה4DBMB؝ىُصذ؍הךꟼ׻׶

  10. ➙傈鑧ֿׅה '0-*0ד㹋ꥷ麊欽׃ג׫גծ 麊欽את׶ًٝذشٝأ䚍ךぢ♳װغؚך幾㼰׃װְׅ ֮׷玎䏝ך倯ꆙָ鋅ִגֹת׃׋կ ׉ֿד猘⦐➂ה׃גך剅ֹ倯ך倯ꆙ׾稱➜׃גְֹתׅկ

  11.  ٌشسزٓٝأؿؓ٦و٦׾ז׷ץֻ㢩鿇ח⳿ׁזְ  %#זוךزٓٝؠؙءّٝⳢ椚דכ琎噰涸ח⢽㢩׾ちֻ  ⶰ⡲欽׾搀椚ח㘗ד邌植׃זְ  %#װ"1*ؙٓ؎،ٝزך鵤⽱⦼ך㘗׾׉ךתת⢪ְ㔐ׁ זְ 剅ֹ倯ך倯ꆙ

  12.  ٌشسزٓٝأؿؓ٦و٦׾ז׷ץֻ㢩鿇ח⳿ׁזְ  %#זוךزٓٝؠؙءّٝⳢ椚דכ琎噰涸ח⢽㢩׾ちֻ  ⶰ⡲欽׾搀椚ח㘗ד邌植׃זְ  %#װ"1*ؙٓ؎،ٝزך鵤⽱⦼ך㘗׾׉ךתת⢪ְ㔐ׁ זְ 剅ֹ倯ך倯ꆙ

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

    def hoge(): Future[Either[FugaException, Unit]] def bar(): Future[Option[Entity]] ྑ͘ͳ͍ͱߟ͍͑ͯΔॻ͖ํ ྑ͍ͱߟ͍͑ͯΔॻ͖ํ
  14. ٌشسزٓٝأؿؓ٦و٦׾ז׷ץֻ㢩鿇ח⳿ׁזְ  ٌشسزٓٝأؿؓ٦و٦ָ䗳銲דזְㄎן⳿׃⯋ד׮ꆤ ׵׸ג♶欽䠐חٌشسزٓٝأؿؓ٦و٦ָ⢪׻׸ג׷  穠卓涸חꟼ侧ꟼ侧׃׋铣׫ב׵ְ؝٦سחז׶ָ׍  䪔ְָ꬗⦜ד׮♧䏝㢌䳔穠卓׾鵤ׅ  ꟼ侧ⰻ鿇דꟗׄג׷ⴓחכ⢪欽׃ג׮圓׻זְ

  15.  ٌشسزٓٝأؿؓ٦و٦׾ז׷ץֻ㢩鿇ח⳿ׁזְ  %#זוךزٓٝؠؙءّٝⳢ椚דכ琎噰涸ח⢽㢩׾ちֻ  ⶰ⡲欽׾搀椚ח㘗ד邌植׃זְ  %#װ"1*ؙٓ؎،ٝزך鵤⽱⦼ך㘗׾׉ךתת⢪ְ㔐ׁ זְ 剅ֹ倯ך倯ꆙ

  16. // 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)) } } %#זוךزٓٝؠؙءّٝⳢ椚דכ琎噰涸ח⢽㢩׾ちֻ ྑ͘ͳ͍ͱߟ͍͑ͯΔॻ͖ํ
  17. 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 () } %#זוךزٓٝؠؙءّٝⳢ椚דכ琎噰涸ח⢽㢩׾ちֻ ྑ͍ͱߟ͍͑ͯΔॻ͖ํ
  18. %#זוךزٓٝؠؙءّٝⳢ椚דכ琎噰涸ח⢽㢩׾ちֻ  5SBOTBDUJPOך㢳ֻכ⢽㢩׾ك٦أחٗ٦ٕغحָؙ遤 ׻׸׷ֿהָ㢳ְ  稆湫ח⢽㢩׾䫎־׷קֲָ鋅鸐׃ָ״ֻז׷  -FGUך佝縧ח״׷ٗ٦ٕغحؙ׃䘌׸ָ饯ֿ׷〳腉䚍 ׾幾׵ׇ׷

  19.  ٌشسزٓٝأؿؓ٦و٦׾ז׷ץֻ㢩鿇ח⳿ׁזְ  %#זוךزٓٝؠؙءّٝⳢ椚דכ琎噰涸ח⢽㢩׾ちֻ  ⶰ⡲欽׾搀椚ח㘗ד邌植׃זְ  %#װ"1*ؙٓ؎،ٝزך鵤⽱⦼ך㘗׾׉ךתת⢪ְ㔐ׁ זְ 剅ֹ倯ך倯ꆙ

  20. 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)) } } } ⶰ⡲欽׾搀椚ח㘗ד邌植׃זְ ྑ͘ͳ͍ͱߟ͍͑ͯΔॻ͖ํ
  21. ⶰ⡲欽׾搀椚ח㘗ד邌植׃זְ @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) } } } ྑ͍ͱߟ͍͑ͯΔॻ͖ํ
  22. ⶰ⡲欽׾搀椚ח㘗ד邌植׃זְ  וֲ׃ג׮3VOUJNFד饯ֿ׏ג׃תֲ׮ךָ֮׷  %#ך״ֲח帾ְٖ؎َ٦ד饯ֿ׷⢽㢩ך㜥さכ㾴׾ת׋ּ䏝ח وحؾָؚٝ䗳銲חז׶撕꧟חז׷  ،فٔ؛٦ءّٝדعٝسٕ׃׋ְ׮ךח穾׶ծ䖓כ㣐劤ךㄎן⳿ ׃⩎דٍؗحثׅ׷הأحׅؗٔ׷ 

    את׶ծ،فٔ؛٦ءّٝך㹋鄲ח꧊⚥דֹ׷
  23.  ٌشسزٓٝأؿؓ٦و٦׾ז׷ץֻ㢩鿇ח⳿ׁזְ  %#זוךزٓٝؠؙءّٝⳢ椚דכ琎噰涸ח⢽㢩׾ちֻ  ⶰ⡲欽׾搀椚ח㘗ד邌植׃זְ  %#װ"1*ؙٓ؎،ٝزך鵤⽱⦼ך㘗׾׉ךתת⢪ְ㔐ׁ זְ 剅ֹ倯ך倯ꆙ

  24. // 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*ؙٓ؎،ٝزך鵤⽱⦼ך㘗׾׉ךתת⢪ְ㔐ׁזְ ྑ͘ͳ͍ͱߟ͍͑ͯΔॻ͖ํ
  25. // 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*ؙٓ؎،ٝزך鵤⽱⦼ך㘗׾׉ךתת⢪ְ㔐ׁזְ ྑ͍ͱߟ͍͑ͯΔॻ͖ํ
  26. 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*ؙٓ؎،ٝزך鵤⽱⦼ך㘗׾׉ךתת⢪ְ㔐ׁזְ ྑ͍ͱߟ͍͑ͯΔॻ͖ํ
  27. %#װ"1*ؙٓ؎،ٝزך鵤⽱⦼ך㘗׾׉ךתת⢪ְ㔐ׁזְ  ⢪ֲ䩛岀ח״׏גכ鵤⽱⦼ָ荈⹛欰䧭ׁ׸ג⤑ⵃ׌ָծ%#װ"1*ؙٓ ؎،ٝزזוכ׋׌ךر٦ةا٦أזךדծ䧮ղָ⡲׶׋ְ،فٔ ؛٦ءّٝהכⴽ暟  臰侁꣇姺㾴זו׾䮠׫ծ䧮ղך،فٔ؛٦ءָّٝ欽䠐ׅ׷㘗ח㢌䳔 ׅ׷ֿהד%#װ"1*ך➬圫㢌刿ח䓼ֻז׷  侧ָ㢳ְהوحؾָؚٝ꬗⦜׌ָծ㛙暕ז،فٔ؛٦ءّٝח鵚בֻ

  28.  '0-*0ה4DBMBךꟼ׻׶׾稱➜  '0-*0דך麊欽ח״׷濼鋅ַ׵ծ⦐➂涸ח葺ְה 罋ִ׷倯ꆙ׾稱➜ תה׭

  29. None
  30. ➰ꐮ

  31.  ؙٔ٦ٝ،٦ؗذؙثٍך䱰欽  ⣛㶷זוךⵖ秈ָ㟓ִծ㹋鄲ָ侔׵ל׵׆ծ䕵ⶴָ僇然חדֹ׷  ،فٔ؛٦ءّٝךسً؎ٝ׾ؾُ،חדֹ׷  稢ְַ㹋鄲כ䖓ח׃גِ٦أ؛٦أ׾鎸鶢דֹ׷  ⡲噟ⴓ䬐ָ֮׷玎䏝דֹ׷

     سً؎ٝ椚鍑ך׋׭ךٙ٦ؙءّحف׾ث٦يדꟚ⪵ ׉ך➭