DDD + Clean Architecture + UCDOM Essence版

DDD + Clean Architecture + UCDOM Essence版

http://ddd-cqrs-es.connpass.com/event/27181/
「Reactive Messaging Patternsプレ読書会 - CQRS、ESの基本を学ぶ -」の資料です。
Embeddedなままだと各種リンクが有効ではないので、気になる方は"Download PDF"よりご参照ください。

Full版はコチラ:https://speakerdeck.com/yoskhdia/ddd-plus-clean-architecture-plus-ucdom-fullban

65cc101435ac36057f2a2c80244c4c6e?s=128

Yoshitaka Okuda

March 16, 2016
Tweet

Transcript

  1. 2.

    About me • ԞాՂڗʢYoshitaka Okudaʣ • גࣜձࣾSocketʢKDDI Syn.ϗʔϧσΟϯάεάϧʔϓʣ
 ΞʔΩςΫτ •

    Twitter @yoskhdia • interested in DDD/Scala/C#/Reactive System/
 Architect/System Thinking/Team Building/
 Agile/ܦӦ৘ใֶ/On-Road Bike
  2. 3.

    Agenda • υϝΠϯۦಈઃܭʢDDDʣ͓͞Β͍ • Clean Architectureͱ͸Կ͔ • DDD + Clean

    Architectureମݧஊ • Ϣʔεέʔεۦಈ։ൃʢICONIXϓϩηεʣʹ ग़ձͬͨ࿩
  3. 7.

    ݴ༿ͷఆٛʢݪଇʣ • υϝΠϯʢDomainʣ • Ϗδωεશମͷ໰୊ྖҬͦͷ΋ͷͷ͜ͱɻιϑτ΢ΣΞͰղܾ͢Δͷ͸ɺ͜ͷҰ෦ɻ • υϝΠϯϞσϧʢDomain Modelʣ • υϝΠϯʹରͯ͠ɺͦͷղܾࡦʢιϦϡʔγϣϯʣΛϞσϧԽͨ͠΋ͷɻ

    • υϝΠϯΤΩεύʔτʢDomain Expertʣ • υϝΠϯʹਫ਼௨͍ͯ͠ΔਓɻҰਓͰ͋Δ͜ͱ΋͋Ε͹ෳ਺ਓͰ͋Δ͜ͱ΋͋Δɻ • ίΞυϝΠϯʢCore Domainʣ • υϝΠϯ͸͍͔ͭ͘ͷྖҬʹ෼ׂ͢Δ͜ͱ͕ଟ͍ɻ͜ͷ࣌ɺҰ൪ϏδωεՁ஋ͷߴ͍ྖ ҬΛίΞυϝΠϯͱ͍͏ɻ࣌ؒ΍ਓ͸༗ݶͳͷͰίΞυϝΠϯΛݟ͚ͭͯɺͦ͜ʹ஫ྗ ͢Δ͜ͱ͕ॏཁɻ
  4. 8.

    ݴ༿ͷఆٛʢݪଇʣ • ϢϏΩλεݴޠʢUbiquitous Languageʣ • ίʔυΛॻ͍͍ͯΔͱΦϨΦϨ໋໊Λ͕ͪ͠ɻ͢ΔͱɺυϝΠϯΤΩεύʔτ ͱ࿩Λ͢Δͱ͖ʹݴ༿ͷ຋༁͕ൃੜ͢Δɻ͜͏ͳΔͱɺυϝΠϯΤΩεύʔτ ͷඳ͘Ϟσϧͱίʔυ͕ဃ཭͍ͯͬͯ͠͠·͏ͷͰɺυϝΠϯΤΩεύʔτΛ ؚΉνʔϜશମͰಉ͡ݴ༿Λ࢖͏Α͏ʹ߹ҙ͢Δɻ •

    ڥք͚ͮΒΕͨίϯςΩετʢBounded Contextʣ • จ຺ʢίϯςΩετʣʹΑͬͯɺಉ͡ݴ༿ͳͷʹҟͳΔҙຯʹͳΔ͜ͱ͕͋Δɻ υϝΠϯϞσϧ͸େ͖͘ͳΓ͕ͪͳͷͰɺҰ؏ੑΛอͬͨ··εέʔϧ͢Δʹ ͸ɺίϯςΩετͷڥքΛϋοΩϦͤͯ͞ҙຯͷมΘΒͳ͍৔ॴΛ࡞Δɻίϯ ςΩετϚοϓͱ͍͏πʔϧΛ࢖ͬͨΓ͢Δɻ
 InfoQʮίϯςΩετϚοϐϯάʹΑΔઓུతυϝΠϯۦಈઃܭʯΛࢀর
  5. 9.

    υϝΠϯͱίϯςΩετͷؔ܎ υϝΠϯ ίϯςΩετ αϒυϝΠϯ ίΞυϝΠϯ • ఺ઢɿ
 υϝΠϯڥք • ੺࣮ઢɿ


    ίϯςΩετڥք • ίϯςΩετ͸͍ ͔ͭ͘ͷυϝΠϯ ڥքʹލΔ͜ͱ͕ ͋Δ • ཧ૝͸αϒυϝΠ ϯͱίϯςΩετ ͕1ର1 αϒυϝΠϯ
  6. 19.

    Hexagonal΍Onionͱૂ͍͸ಉ͡ • ϑϨʔϜϫʔΫͱ͍͏੍໿ʹγεςϜΛ٧ΊࠐΉͷ Ͱ͸ͳ͘ɺγεςϜʹϑϨʔϜϫʔΫΛ౰ͯ͸ΊΔ • ϑϨʔϜϫʔΫ͔Βಠཱ͢Δ ㅟ ㅟ ㅟ ㅟ

    • UI͔Βಠཱ͢Δ ㅟ ㅟ ㅟ ㅟ • σʔλϕʔε͔Βಠཱ͢Δ ㅟ ㅟ ㅟ ㅟ • ೚ҙͷ֎෦ϦιʔεɺαʔϏε͔Βಠཱ͢Δ ㅟ ㅟ ㅟ ㅟ
  7. 21.

    ཁࢫ • ඇৗʹγϯϓϧͳϧʔϧͳͷͰ෼͔Γ΍͍͢ • ૚Ͱ෼཭ • େ੾ͳ΋ͷΛ಺ଆʹஔ͘ • ґଘؔ܎نଇʢ಺ଆʹͷΈґଘʣΛकΔ •

    ಠཱੑ͸ςετͷ༰қੑʹ΋ߩݙ͢Δ • ٕज़͕ݹ͘ͳͬͨΒ࠷খݶͷखؒͰަ׵Ͱ͖Δ • ϑϨʔϜϫʔΫΛަ׵͢Δ͜ͱ͸͋ͬͯ΋ɺυϝΠϯ஌ࣝΛަ׵ ͢Δͱ͍͏ͷ͸͋Γಘͳ͍
  8. 25.

    ύοέʔδߏ੒ • Domain(Entities)૚ • Contract૚ • Domain૚ͱͷڮ౉͠
 ʢDIΛ࢖͏ͷͰΠϯλϑΣʔε͸ผʹ͍ͯ͠Δʣ • UseCase૚

    • Adapter૚ • Repositoryͷ࣮૷Ϋϥε΋͜͜ • ʢExternal૚ʣ • ϑϨʔϜϫʔΫ΍ϥΠϒϥϦͷ૚ͱ͍͏Ґஔ͚ͮ ̐૚Ͱͳͯ͘΋0,
  9. 28.

    Use Case import scala.concurrent.{ExecutionContext, Future}
 
 trait UseCase {
 type

    In
 
 type Out
 
 protected def call(arg: In)(implicit ec: ExecutionContext): Future[Out]
 } "EBQUFS૚ͱͷ࿈ܞ͸1PSUʹҕৡ
  10. 29.

    Input Port import scala.concurrent.ExecutionContext
 import scala.util.{Failure, Success}
 trait PushPort[Arg, Result]

    {
 self: UseCase =>
 
 override final type In = Arg
 
 override final type Out = Result
 
 def execute[T <: Callback[Result]](arg: Arg)(callback: T)
 (implicit ec: ExecutionContext): Unit = {
 call(arg).onComplete {
 case Success(result) =>
 callback.onSuccess(result)
 case Failure(t) =>
 callback.onFailure(t)
 }
 }
 } "EBQUFS૚͔ΒͲ͏໯͏͔ ԿΛฦ͔͢Λఆٛ *OQVU1PSUͷ໾ׂ͸ ड͚औΔ͜ͱ·ͰͳͷͰ 6OJUΛฦ͢
  11. 30.

    Output Port trait Callback[Result] {
 
 def onSuccess(result: Result): Unit


    
 def onFailure(t: Throwable): Unit
 } ΞϓϦέʔγϣϯϩδοΫͷΤϥʔ΋ ಛผͳ&YDFQUJPOΛ༻ҙͯ͠ฦ͢Α͏ʹ͍ͯ͠Δ ʢ+BWBͷ׳शʹ͍ۙʣ ※Callback vs Promise(Future)͸Full൛Ͱิ଍
  12. 32.

    Use Caseͷఆٛ package contract.usecase
 
 import contract.{PushPort, UseCase}
 import domain.{GroupId,

    UserId}
 
 trait PickLeaderUseCase extends UseCase with PushPort[GroupId, UserId] ࣮͸αϘ͍ͬͯΔ 6TF$BTF૚Ͱѻ͍΍͍͢ ΦϒδΣΫτ %50 ʹ͢Δ
  13. 33.

    Use Caseͷ࣮૷ package usecase
 
 import javax.inject.Inject
 import contract.usecase.PickLeaderUseCase
 import

    domain.UserRepository
 
 import scala.concurrent.{ExecutionContext, Future}
 
 class PickLeaderUseCaseImpl @Inject()(userRepository: UserRepository) extends PickLeaderUseCase {
 
 override protected def call(groupId: In) (implicit ec: ExecutionContext): Future[Out] = {
 userRepository.findBy(groupId).map { board =>
 board.pickLeader // ୭ΛͲ͏Ϧʔμʹ͢Δ͔͸υϝΠϯ஌ࣝ
 }
 }
 } ΠϯλϑΣʔεΛ࢖͏ %*ͰґଘΛ୯ํ޲ʹ
  14. 35.

    Controller import contract.usecase.PickLeaderUseCase
 import domain.GroupId
 import play.api.data._
 import play.api.libs.concurrent.Execution.Implicits.defaultContext
 import

    play.api.mvc.{Action, Controller}
 
 class GroupController @Inject() (useCase: PickLeaderUseCase, presenter: PickedLeaderPresenter) extends Controller { 
 val form: Form[GroupId] = ??? // ׂѪ
 def pickLeader = Action.async { implicit request =>
 form.bindFromRequest.fold(_ => Future.successful(BadRequest("…")), (groupId: GroupId) =>
 presenter.response(useCase.execute(groupId))
 )
 }
 } ͜ͷॻ͖ํʹ͍ͭͯ͸'VMM൛Ͱิ଍ ೖྗσʔλ͔Βͷม׵͕੹຿
  15. 36.

    Presenter import contract.callback.PickedLeaderCallback
 import domain.UserId
 import play.api.libs.json.Json
 import scala.concurrent.{ExecutionContext, Future,

    Promise}
 
 class PickedLeaderPresenter extends Presenter[PickedLeaderCallback] {
 
 implicit val writer = Json.writes[UserId]
 
 override def response(call: UseCaseExecutor) (implicit ec: ExecutionContext): Future[Rendered] = {
 val callback = new CallbackImpl
 call(callback)
 callback.promise.future.map { userId =>
 Ok(Json.toJson(userId))
 }
 }
 } ग़ྗσʔλ΁ͷม׵͕੹຿
  16. 39.

    ୊ࡐ֓ཁ • ϑϩϯτͱAjaxͰ΍ΓऔΓ͢ΔAPIαʔϏε • ݱߦͰ͸RailsͰ࡞ΒΕ͍ͯͯɺࠓճ͸ϦϓϨʔε • ࢓༷͸ݱߦ౿ऻ • Ϟσϧ͸ActiveRecord͔Β୤٫ •

    Scala + Play! Framework • ߴෛՙ • ग़དྷΔݶΓ1౓ͷϦΫΤετʹ͓͞Ί͍ͨ • σʔλετΞͳͲ֎෦Ϧιʔε΁ͷΞΫηε͕ूத @@'MJQEFTL@@
  17. 40.

    DDD + Clean ArchitectureͰ σʔλΞΫηεΛίϯτϩʔϧ༰қʹ • DDDʹै͏ͱRepositoryΛ࢖͏ݸॴ͸ΞϓϦέʔγϣ ϯαʔϏεʢUseCaseʣ͔υϝΠϯαʔϏεʹݶఆ͞ Ε͍ͯ͘ •

    ू໿(Aggregate)͕ϥΠϑαΠΫϧ·Ͱ୲͏ͱ੹຿ ͕େ͖͘ͳΓ͗͢ΔʢIDDD p.254ʣ • ࣗવͱσʔλΞΫηεݸॴ͕෼͔Γ΍͘͢ ※υϝΠϯαʔϏεɿෳ਺ͷΤϯςΟςΟʹ·͕ͨΔৼΔ෣͍ͳͲɺΤϯςΟςΟ͕ ࣋ͭʹ͸ద͞ͳ͍ৼΔ෣͍Λఆٛͨ͠υϝΠϯΦϒδΣΫτ
  18. 41.

    DDD + Clean ArchitectureͰ σʔλΞΫηεΛίϯτϩʔϧ༰қʹ • ࠓͷͱ͜ΖυϝΠϯαʔϏεͰRepositoryΛ࢖͍͍ͨέʔε͸ग़͍ͯ ͳ͍ͷͰɺUseCaseͰͷΈRepositoryΛ࢖͑ΔΑ͏ʹͯ͠ࢼ͍ͯ͠Δ • ҙਤͤͣԿ౓΋ݺͼग़ͯ͠͠·͏Մೳੑ͕͋Δˍ࢖͑Δঢ়ଶͩͱ࢖

    ͍ͨ͘ͳΔͷ͕ਓ৘ͳͷͰActiveRecordͷೋͷ෣͍ʹͳΒͳ͍Α͏ ஫ҙΛ෷͍ͬͯΔ • ґଘؔ܎نଇʹΑͬͯ૚͕ด͡ΒΕ͍ͯΔͷͰɺͲ͜ͰσʔλΞΫ ηε͍ͯ͠Δ͔෼͔Γ΍͘͢ͳͬͨ • σʔλετΞ͕Ұ൪֎ͳͷͰަ׵͕͠΍͘͢ͳͬͨɻElasticsearch ൛ͱDynamo൛ͰύϑΥʔϚϯεൺֱ͔ͯ͠Β࠾༻ΛܾΊΔ౳Մೳ
  19. 43.

    τϥϯβΫγϣϯʹ͍ͭͯ • "ू໿ʢAggregateʣ͸τϥϯβΫγϣϯ੔߹ੑͷڥքͱಉٛ" ʢIDDD p.340ʣͳͷͰɺҰͭͷू໿Λѻ͍ͬͯΔؒ͸Repositoryͷ தʹด͡Δ͜ͱ͕Ͱ͖Δɻ • ໰୊͸ɺෳ਺ͷू໿ͷߋ৽Λ୯ҰͷτϥϯβΫγϣϯ಺ͰߦΘͳ͚ Ε͹͍͚ͳ͍࣌ 1.

    ݁Ռ੔߹ੑͰे෼Ͱ͸ͳ͍͔Λݕ౼͢Δ
 ˠτϥϯβΫγϣϯͷແ͍ੈք΁ʢႈ౳ͳૢ࡞͸ඞཁʣ 2. ৽͍͠ू໿ͱͯ͠ఆٛ͢Δ
 ˠ͜ΕΛ܁Γฦ͢ͱڊେͳू໿ʹͳͬͯ͠·͏ͷͰ஫ҙ
  20. 46.

    ͍͟DDDΛ࣮ફ͠Α͏ͱ͢Δͱ • Կ͔Β࢝Ίͯྑ͍͔෼͔Βͳ͍ • υϝΠϯΤΩεύʔτͱͲ͏࿩ͤ͹ྑ͍͔෼͔Βͳ͍ • UIແ͠ͰυϝΠϯ͚ͩΛ࿩ͯ͠΋্ख͘఻ΘΒͳ͍ • ࠷ॳ͔ΒৄࡉͳΫϥεਤΛॻ͜͏ͱͯ͠͠·͏ •

    ࢼ͠ʹϞσϧ͚ͩͰ΋ॻ͍ͯΈΔͱࢥ͍ͷ֎ϘϦϡʔϛΟ • υϝΠϯϞσϧʢΫϥεਤʣ͔Β࢓༷ΛಡΈऔΔͷ͕ࠔ೉ • ૝૾ͯ͠ಡΈऔΖ͏ͱ͢Δͱᐆດ͞ʹ௚໘͢Δ ㅟ ㅟ ㅟ ※ฐࣾࣄྫ͚ͩͰͳ͘ໝ૝΋ؚ·Ε·͢
  21. 52.

    ॻ੶ ʮϢʔεέʔεۦಈ։ൃ࣮ફΨΠυʯ • Use Case Driven Object Modeling with UML

    • ICONIXϓϩηεͷղઆຊ • ඇৗʹܰշͳޠΓޱʢ͏ͻΌʔͱ͔ग़ͯ͘Δʣ • एׯXP൱ఆʢߟ͑ࣗମ͸XPΑΓલ͔Β͋Δʣ • ͍͖ͳΓઃܭʹೖΔͷͰ͸ͳͯ͘ɺ·ͣ͸෼ੳΛͪΌΜͱ͠Α͏ɻ • ಛʹʮՄೳͳݶΓ؆୯ʹ(DTSTTCPW)ʯͱʮͦΜͳ΋ͷ͸ඞཁͳ͍ (YAGNI)ʯΛཧ༝ʹ୅ସίʔεʢΤϥʔέʔεʣΛߟྀʹؚΊͳ͍ ͜ͱ͸ഁ໓΁ͷಓͱ͍ͯ͠Δɻ
  22. 61.

    ద༻΁ͷߟ࡯̎ ੔߹ੑཁٻͷݕ౼ • ސ٬͕ࢀՃ͢ΔϨϏϡʔ͸༧උઃܭϨϏϡʔ·ͰʢγʔέϯεਤҎ ߱͸ٕज़త͗͢ΔʣɻؾΛ͚ͭͳ͍ͱϩόετωε෼ੳͷஈ֊Ͱ ͸੔߹ੑཁٻͷදݱ·Ͱٴ͹ͳ͍ؾ͕͢Δɻ • શͯʹτϥϯβΫγϣϯ͕ඞཁͱ͸ݶΒͣɺ݁Ռ੔߹ੑͰे෼ ͳέʔε΋ଟ͍͸ͣɻ •

    ༧උઃܭϨϏϡʔͷஈ֊·Ͱʹ੔߹ੑͷཁٻʢϨϕϧʣʹ͍ͭ ͯݕ౼ͨ͠ํ͕ྑ͍ͱࢥ͏ɻ • "τϥϯβΫγϣϯͷ෼ੳΛ͔ͯ͠ΒͰͳ͍ͱɺू໿ͷઃܭͷྑ ͠ѱ͠Λਖ਼͘͠൑அ͢Δ͜ͱ͸Ͱ͖ͳ͍"ʢIDDD p.340-344ʣ
  23. 66.

    ·ͱΊ • DDD
 + Clean Architecture
 + Use Case Driven

    Object Modeling(ICONIX)
 ͷηοτ͸૬ੑ͕ྑͦ͞͏ • ICONIX͸ܰྔͱ͸͍͑ɺͦͷதͰ΋Ͳ͜·ͰΛ࣮ࢪ͢Δ͔ ސ٬΍νʔϜͱςʔϥϦϯάͨ͠ํ͕ྑ͍͔΋ • ֖Λ։͚Ε͹஌͍ͬͯΔਓʹ͸౰ͨΓલ…
 ૣ͘஌Γ͔ͨͬͨ
 ʢଞͷ࣮ફख๏΋͝ଘ஌ͷํ͕͍Βͬ͠ΌΕ͹ޙͰڭ͍͑ͯͩ͘͞ʣ
  24. 67.
  25. 68.

    ࢀߟɿDDDฤ • ॻ੶ʮΤϦοΫɾΤϰΝϯεͷυϝΠϯۦಈઃܭʯʢᠳӭࣾʣ • ॻ੶ʮ࣮ફυϝΠϯۦಈઃܭʯʢᠳӭࣾʣ • ਿຊ ܒ ࢯʮυϝΠϯۦಈઃܭ at

    DDD.rb #5ʯ • ਿຊ ܒ ࢯʮ2ͭͷυϝΠϯϞσϧʕDDDͷؚҙʯ • ૿ా ږ ࢯʮ3ि࿈ଓDDDͦͷ1 υϝΠϯۦಈઃܭͷجຊΛཧղ͢Δʯ • ૿ా ږ ࢯʮ3ि࿈ଓDDDͦͷ2 ਂ͍Ϟσϧͷ୳ٻ(υϝΠϯۦಈઃܭ ୈ̏෦) ʯ • ૿ా ږ ࢯʮ3ि࿈ଓDDDͦͷ3 υϝΠϯۦಈઃܭ ઓུతઃܭ ʯ • InfoQʮυϝΠϯۦಈઃܭɾ։ൃͷ࣮ફʯ • InfoQʮίϯςΩετϚοϐϯάʹΑΔઓུతυϝΠϯۦಈઃܭʯ • InfoQʮShane HastieࢯɺϏδωε՝୊ʹର͢ΔΞδϟΠϧϚΠϯυηοτͷద༻ʹ͍ͭͯޠΔʯ
  26. 69.

    ࢀߟɿClean Architectureฤ • ετϥςδοΫνϣΠεʮϨΠϠʔυΞʔΩςΫνϟʯ • Alistair Cockburn ࢯʮHexagonal Architectureʯʢ຋༁ɿ෢౻ ࢯʣ

    • Jeffrey Palermo ࢯʮThe Onion Architectureʯ • Robert Martin ࢯʮThe Clean Architectureʯʢ຋༁ɿ෢౻ ࢯʣ • Thomas PIERRAIN ࢯʮA zoom on the hexagonal/clean/onion architectureʯ • InfoQʮυϝΠϯۦಈઃܭͱΦχΦϯΞʔΩςΫνϟʯ • InfoQʮΞʔΩςΫνϟͷ໨త͸ҙਤͰ͋ΓɺϑϨʔϜϫʔΫͰ͸ͳ͍ʯ • James Coglan ࢯʮ໋ྩܕͷίʔϧόοΫɺؔ਺ܕͷϓϩϛε: Node ͕ҳͨ͠࠷େͷػձʯ(຋༁ɿԬຊ ࢯ) • Togetter·ͱΊʮ”໋ྩܕͷίʔϧόοΫɺؔ਺ܕͷϓϩϛε”΁ͷ൓Ԡʢͱͦͷޙʣʯ • _kondeiࢯʮ࣋ଓՄೳͳ։ൃΛ໨ࢦ͢ ~ υϝΠϯɾϢʔεέʔεۦಈʢΫϦʔϯΞʔΩςΫνϟʣ + ୯ํ޲ʹ੍ݶͨ͠ॲཧ + FRPʯ • ૿ా ږ ࢯʮυϝΠϯϞσϧத৺ͷΞʔΩςΫνϟʯ
  27. 70.

    ࢀߟɿϢʔεέʔεۦಈ։ൃฤ • ॻ੶ʮϢʔεέʔεۦಈ։ൃ࣮ફΨΠυʯʢᠳӭࣾʣ • ॻ੶ʮΤΫετϦʔϜϓϩάϥϛϯάୈ2൛৽༁ʯʢΦʔϜࣾʣ • ॻ੶ʮϢʔβʔετʔϦʔϚοϐϯάʯʢΦϥΠϦʔδϟύϯʣ • ૿ా ږ

    ࢯʮ࣮ફ ICONIXϓϩηεɿγʔέϯεਤͱΫϥεਤʯ • ૿ా ږ ࢯʮ࣮ફ ICONIXϓϩηεɿυϝΠϯۦಈʯ • WikipediaʮICONIXϓϩηεʯ • EZʮϏδωεཁٻͷٸܹͳมԽʹରԠ͢Δ։ൃϓϩηεͱ͸ʁʯ