Slide 1

Slide 1 text

4DBMBͰ΢Σϒ"1*Λॻ͍͍ͯΔਓ͕ ઃܭ΍࣮૷΍ͦͷଞʹ͍ͭͯ࿩ͦ͏͔ JO:TQSJOHJO4IJCVZB

Slide 2

Slide 2 text

ࣗݾ঺հ ໊લͨͬ͘Μ w (JU)VCUBLLLVO w 5XJUUFSUBLLLVOʢΞΠίϯ͸ˠʣ ॴଐגࣜձࣾϝσΟϩϜ ۀ຿4DBMBͰαʔόαΠυશൠ

Slide 3

Slide 3 text

IUUQTHJUIVCDPNUBLLLVOZTBNQMFBQQ

Slide 4

Slide 4 text

ΞʔΩςΫνϟ

Slide 5

Slide 5 text

ΞʔΩςΫνϟͷ࡞༻ w ΞϓϦέʔγϣϯʹ͸༷ʑͳؔ৺͕͋Δ w ղܾ͍ͨ͠໰୊ʹର͢Δॲཧͦͷ΋ͷʢػೳཁ݅ʣ w ೖྗํࣜ w ग़ྗํࣜ w ӬଓԽ w FUD w ۪௚ʹॻ͍ͯ͸ؔ৺͕ࠞ͟Γ߹͏ w ؔ৺Λ෼ׂ͢Δ͜ͱ͕େࣄɻΞʔΩςΫνϟ͸ͦͷͨΊͷख๏

Slide 6

Slide 6 text

ϨΠϠʔυΞʔΩςΫνϟ ϓϨθϯςʔγϣϯ૚ ΞϓϦέʔγϣϯ૚ υϝΠϯ૚ ΠϯϑϥετϥΫνϟ૚ ֤૚ͷґଘؔ܎ "ˠ#"͸#ʹґଘ͢Δ

Slide 7

Slide 7 text

֤૚ͷґଘؔ܎ "ˠ#"͸#ʹґଘ͢Δ ͢΂ͯͷ૚͕ΠϯϑϥετϥΫνϟ૚ ʹґଘ͍ͯ͠Δɻ͜͏ͳ͍ͬͯΔͱ w ΠϯϑϥετϥΫνϟ૚ͷ౎߹ʹҾ ͖ͣΒΕΔ w ςετ࣌ʹΠϯϑϥετϥΫνϟ૚ Λ४උ͢Δඞཁ͕͋Δ ϨΠϠʔυΞʔΩςΫνϟ ϓϨθϯςʔγϣϯ૚ ΞϓϦέʔγϣϯ૚ υϝΠϯ૚ ΠϯϑϥετϥΫνϟ૚

Slide 8

Slide 8 text

ґଘؔ܎ٯసͷݪଇʢ%*1ʣ ఻౷తͳϨΠϠʔυΞʔΩςΫνϟ υϝΠϯ૚͕ΠϯϑϥετϥΫνϟ૚ Λ௚઀ར༻ υϝΠϯ૚ ΠϯϑϥετϥΫνϟ૚

Slide 9

Slide 9 text

ґଘؔ܎ٯసͷݪଇʢ%*1ʣ ఻౷తͳϨΠϠʔυΞʔΩςΫνϟ υϝΠϯ૚͕ΠϯϑϥετϥΫνϟ૚ Λ௚઀ར༻ υϝΠϯ૚ ΠϯϑϥετϥΫνϟ૚ %*1ʹΑΔϨΠϠʔυΞʔΩςΫνϟ  υϝΠϯ૚ͰinterfaceΛఆٛ͠  ͦΕΛΠϯϑϥετϥΫνϟ૚Ͱ ࣮૷ υϝΠϯ૚ ΠϯϑϥετϥΫνϟ૚

Slide 10

Slide 10 text

੔ཧ͞ΕͨϨΠϠʔυΞʔΩςΫνϟ ΠϯϑϥετϥΫνϟ૚ ϓϨθϯςʔγϣϯ૚ ΞϓϦέʔγϣϯ૚ υϝΠϯ૚

Slide 11

Slide 11 text

੔ཧ͞ΕͨϨΠϠʔυΞʔΩςΫνϟ ΠϯϑϥετϥΫνϟ૚ ϓϨθϯςʔγϣϯ૚ ΞϓϦέʔγϣϯ૚ υϝΠϯ૚ IUUQTUIMJHIUDPNCMPHVODMFCPCUIFDMFBO BSDIJUFDUVSFIUNM

Slide 12

Slide 12 text

υϝΠϯ૚

Slide 13

Slide 13 text

ؔ৺Λ੔ཧ ٕज़ͷؔ৺ w σʔλετΞ͸1PTUHSF42- w ੩తϑΝΠϧ͸"NB[PO4 w ϦΫΤετ͸)551Ͱड͚෇͚Δ w FUD ۀ຿ͷؔ৺ w λΠτϧΛࢦఆͯ͠λεΫΛ࡞Δ w λεΫΛऴྃ͢Δ w λεΫ͕ऴྃࡁΈͷ৔߹͸Τϥʔ w FUD

Slide 14

Slide 14 text

ؔ৺Λ੔ཧ ٕज़ͷؔ৺ w σʔλετΞ͸1PTUHSF42- w ੩తϑΝΠϧ͸"NB[PO4 w ϦΫΤετ͸)551Ͱड͚෇͚Δ w FUD Ϗδωε্ͷ֓೦΍ϧʔϧ ۀ຿ͷؔ৺ w λΠτϧΛࢦఆͯ͠λεΫΛ࡞Δ w λεΫΛऴྃ͢Δ w λεΫ͕ऴྃࡁΈͷ৔߹͸Τϥʔ w FUD

Slide 15

Slide 15 text

υϝΠϯۦಈઃܭʢ%%%ʣ w ΞϓϦέʔγϣϯͷؔ܎ऀʢղܾ͍ͨ͠໰୊ͷઐ໳ՈυϝΠϯΤΩεύʔ τɺ։ൃऀɺFUDʣશһͷڞ௨ݴޠͱͳΔϢϏΩλεݴޠΛཱ֬ w ϢϏΩλεݴޠΛ༻͍ͯϏδωε্ͷ֓೦΍ϧʔϧΛϞσϦϯάʢυϝΠϯ Ϟσϧʣ w υϝΠϯϞσϧΛίʔυʹ൓ө͢Δ͜ͱͰɺݴޠͱϞσϧͱίʔυ͕࿈ಈ

Slide 16

Slide 16 text

υϝΠϯۦಈઃܭʢ%%%ʣ w ΞϓϦέʔγϣϯͷؔ܎ऀʢղܾ͍ͨ͠໰୊ͷઐ໳ՈυϝΠϯΤΩεύʔ τɺ։ൃऀɺFUDʣશһͷڞ௨ݴޠͱͳΔϢϏΩλεݴޠΛཱ֬ w ϢϏΩλεݴޠΛ༻͍ͯϏδωε্ͷ֓೦΍ϧʔϧΛϞσϦϯάʢυϝΠϯ Ϟσϧʣ w υϝΠϯϞσϧΛίʔυʹ൓ө͢Δ͜ͱͰɺݴޠͱϞσϧͱίʔυ͕࿈ಈ ্هΛ܁Γฦ͠ߦ͍ɺΑΓ༗༻ͳϞσϧΛखʹೖΕΔ

Slide 17

Slide 17 text

υϝΠϯϞσϧΛදݱ͢Δཁૉ w ஋ΦϒδΣΫτ w ΤϯςΟςΟ w αʔϏε w ϦϙδτϦ w ϑΝΫτϦ w ू໿ w υϝΠϯΠϕϯτ

Slide 18

Slide 18 text

υϝΠϯϞσϧΛදݱ͢Δཁૉ w ஋ΦϒδΣΫτ w ΤϯςΟςΟ w αʔϏε w ϦϙδτϦ w ϑΝΫτϦ w ू໿ w υϝΠϯΠϕϯτ

Slide 19

Slide 19 text

஋ΦϒδΣΫτ w υϝΠϯͷ֓೦Λදͨ͢ΊͷෆՄ෼ͳଐੑͷू߹ w ྫ͑͹ʮλΠτϧʯͻͱͭͷଐੑ͔࣋ͨ͠ͳ͍͕ɺυϝΠϯͷ֓೦Λද͢ ͨΊʹ஋ΦϒδΣΫτΛར༻ w ྫ͑͹ʮ੏໊ʯ੏ͱ໊ɺ;ͨͭͷଐੑ͕͋ͬͯ࢝Ίͯ੒Γཱͭ

Slide 20

Slide 20 text

஋ΦϒδΣΫτͷಛ௃ ෆม ஋ΦϒδΣΫτΛ࡞੒ͨ͠ޙʹॴ༗͢ΔଐੑΛมߋ͢Δ͜ͱ͕ग़དྷͳ͍ɻ ଐੑʹΑΔ౳Ձ ผͷ஋ΦϒδΣΫτͱൺ΂ͨͱ͖ɺॴ༗͢ΔଐੑͦΕͧΕ͕౳ՁͰ͋Δ৔߹ ʹ஋ΦϒδΣΫτͦͷ΋ͷ͕౳ՁͰ͋ΔͱΈͳ͢ɻ

Slide 21

Slide 21 text

έʔεΫϥεͷར༻ w GBNJMZ/BNF HJWFO/BNFΛ֎෦ʹॻ͖׵͑ෆՄೳͳܗͰެ։ w GBNJMZ/BNF HJWFO/BNFͦΕͧΕ͕౳Ձͷ৔߹ʹΦϒδΣΫτࣗମ͕౳Ձ ͱͳΔΑ͏FRVBMT IBTI$PEFΛΦʔόϥΠυ w DPQZϝιουΛఆٛ w /BNFΦϒδΣΫτʹBQQMZΛఆٛʢOFXͳ͠ͷΠϯελϯεੜ੒ʣ w /BNFΦϒδΣΫτʹVOBQQMZΛఆٛʢύλʔϯϚον΁ͷར༻ʣ w FUD case class Name(familyName: String, givenName: String)

Slide 22

Slide 22 text

έʔεΫϥεͷར༻ w GBNJMZ/BNF HJWFO/BNFΛ֎෦ʹॻ͖׵͑ෆՄೳͳܗͰެ։ w GBNJMZ/BNF HJWFO/BNFͦΕͧΕ͕౳Ձͷ৔߹ʹΦϒδΣΫτࣗମ͕౳Ձ ͱͳΔΑ͏FRVBMT IBTI$PEFΛΦʔόϥΠυ w DPQZϝιουΛఆٛ w /BNFΦϒδΣΫτʹBQQMZΛఆٛʢOFXͳ͠ͷΠϯελϯεੜ੒ʣ w /BNFΦϒδΣΫτʹVOBQQMZΛఆٛʢύλʔϯϚον΁ͷར༻ʣ w FUD ஋ΦϒδΣΫτͷʮෆมʯͱʮଐੑʹΑΔ౳Ձʯɺ;ͨͭͷੑ࣭Λຬͨ͢ case class Name(familyName: String, givenName: String)

Slide 23

Slide 23 text

έʔεΫϥεͷར༻ w GBNJMZ/BNF HJWFO/BNFΛ֎෦ʹॻ͖׵͑ෆՄೳͳܗͰެ։ w GBNJMZ/BNF HJWFO/BNFͦΕͧΕ͕౳Ձͷ৔߹ʹΦϒδΣΫτࣗମ͕౳Ձ ͱͳΔΑ͏FRVBMT IBTI$PEFΛΦʔόϥΠυ w DPQZϝιουΛఆٛ w /BNFΦϒδΣΫτʹBQQMZΛఆٛʢOFXͳ͠ͷΠϯελϯεੜ੒ʣ w /BNFΦϒδΣΫτʹVOBQQMZΛఆٛʢύλʔϯϚον΁ͷར༻ʣ w FUD case class Name(familyName: String, givenName: String) ֎෦ʹରͯ͠ෆཁͳΠϯλϑΣʔεΛ࢈Ή

Slide 24

Slide 24 text

஋ΦϒδΣΫτͷఆٛྫ sealed trait Name { def familyName: String def givenName: String } private case class NameImpl( familyName: String, givenName: String ) extends Name object Name { def apply(familyName: String, givenName: String): Name = NameImpl(familyName, givenName) }

Slide 25

Slide 25 text

஋ΦϒδΣΫτͷఆٛྫ sealed trait Name { def familyName: String def givenName: String } private case class NameImpl( familyName: String, givenName: String ) extends Name object Name { def apply(familyName: String, givenName: String): Name = NameImpl(familyName, givenName) } /BNF͸TFBMFEUSBJUͰఆٛ TFBMFEम০ࢠ/BNF͕ఆٛ͞ΕͨϑΝΠϧҎ֎Ͱͷܧঝېࢭ

Slide 26

Slide 26 text

஋ΦϒδΣΫτͷఆٛྫ sealed trait Name { def familyName: String def givenName: String } private case class NameImpl( familyName: String, givenName: String ) extends Name object Name { def apply(familyName: String, givenName: String): Name = NameImpl(familyName, givenName) } /BNFΛܧঝͨ͠έʔεΫϥεΛఆٛ

Slide 27

Slide 27 text

஋ΦϒδΣΫτͷఆٛྫ sealed trait Name { def familyName: String def givenName: String } private case class NameImpl( familyName: String, givenName: String ) extends Name object Name { def apply(familyName: String, givenName: String): Name = NameImpl(familyName, givenName) } /BNFܕͰ/BNF*NQMΫϥεͷΠϯελϯεΛฦ͢ ࣮ଶ͸/BNF*NQMΫϥεͳͷͰέʔεΫϥεͷಛੑΛ͕࣋ͭɺܕͱͯ͠͸/BNFܕͳͷͰɺ DPQZϝιουͳͲΛݺͼग़͢͜ͱ͸ग़དྷͳ͍

Slide 28

Slide 28 text

ΤϯςΟςΟ w ஋ΦϒδΣΫτͱಉ༷υϝΠϯͷ֓೦Λදͨ͠΋ͷ w ඞͣࣝผࢠΛ࣋ͭ w ஋ΦϒδΣΫτͱൺ΂ͯ w Մมʢଐੑ͸มΘΓಘΔʣ w ࣝผࢠಉ͕࢜౳ՁͰ͋Ε͹ɺͦͷଞଐੑʹؔΘΒͣΤϯςΟςΟಉ࢜͸ಉ ҰͰ͋ΔͱΈͳ͢ w ྫ͑͹ʮλεΫʯλεΫ͕ऴྃͨ͠ͱͯ͠΋ɺݩͷλεΫͱ͸ಉҰͷଘࡏ Ͱ͋Δ

Slide 29

Slide 29 text

ΤϯςΟςΟͷϕʔε trait Entity[ID] { def id: ID override def equals(obj: Any): Boolean = obj match { case that: Entity[_] => id == that.id case _ => false } override def hashCode(): Int = 31 * id.## }

Slide 30

Slide 30 text

ΤϯςΟςΟͷϕʔε trait Entity[ID] { def id: ID override def equals(obj: Any): Boolean = obj match { case that: Entity[_] => id == that.id case _ => false } override def hashCode(): Int = 31 * id.## } ࣝผࢠJEΛ࣋ͪɺͦͷܕΛද͢*%ܕύϥϝʔλΛड͚औΔ

Slide 31

Slide 31 text

ΤϯςΟςΟͷϕʔε trait Entity[ID] { def id: ID override def equals(obj: Any): Boolean = obj match { case that: Entity[_] => id == that.id case _ => false } override def hashCode: Int = 31 * id.## } JEʹΑͬͯFRVBMTͱIBTI$PEFΛΦʔόϥΠυ

Slide 32

Slide 32 text

ΤϯςΟςΟͷఆٛྫ case class TaskId(value: UUID) class Task( val id: TaskId, val title: TaskTitle, val createdAt: DateTime, val finishedAt: Option[DateTime] ) extends Entity[TaskId] { def isFinished: Boolean = finishedAt.nonEmpty def finish(): Task = { if (isFinished) { throw new TaskAlreadyFinished(this) } new Task(id, title, createdAt, Some(DateTime.now)) } }

Slide 33

Slide 33 text

case class TaskId(value: UUID) class Task( val id: TaskId, val title: TaskTitle, val createdAt: DateTime, val finishedAt: Option[DateTime] ) extends Entity[TaskId] { def isFinished: Boolean = finishedAt.nonEmpty def finish(): Task = { if (isFinished) { throw new TaskAlreadyFinished(this) } new Task(id, title, createdAt, Some(DateTime.now)) } } ΤϯςΟςΟͷఆٛྫ ࣝผࢠͱͳΔ5BTL*EΛ஋ΦϒδΣΫτͱͯ͠ఆٛ

Slide 34

Slide 34 text

case class TaskId(value: UUID) class Task( val id: TaskId, val title: TaskTitle, val createdAt: DateTime, val finishedAt: Option[DateTime] ) extends Entity[TaskId] { def isFinished: Boolean = finishedAt.nonEmpty def finish(): Task = { if (isFinished) { throw new TaskAlreadyFinished(this) } new Task(id, title, createdAt, Some(DateTime.now)) } } ΤϯςΟςΟͷఆٛྫ &OUJUZ<5BTL*E>Λܧঝ͠ɺΤϯςΟςΟͷಛੑΛ࣋ͨͤΔ

Slide 35

Slide 35 text

case class TaskId(value: UUID) class Task( val id: TaskId, val title: TaskTitle, val createdAt: DateTime, val finishedAt: Option[DateTime] ) extends Entity[TaskId] { def isFinished: Boolean = finishedAt.nonEmpty def finish(): Task = { if (isFinished) { throw new TaskAlreadyFinished(this) } new Task(id, title, createdAt, Some(DateTime.now)) } } ΤϯςΟςΟͷఆٛྫ 5BTL͕࣋ͭଐੑΛఆٛ

Slide 36

Slide 36 text

case class TaskId(value: UUID) class Task( val id: TaskId, val title: TaskTitle, val createdAt: DateTime, val finishedAt: Option[DateTime] ) extends Entity[TaskId] { def isFinished: Boolean = finishedAt.nonEmpty def finish(): Task = { if (isFinished) { throw new TaskAlreadyFinished(this) } new Task(id, title, createdAt, Some(DateTime.now)) } } ΤϯςΟςΟͷఆٛྫ มߋ͢ΔଐੑΛઃఆͨ͠৽ͨͳΤϯςΟςΟΛฦ͢

Slide 37

Slide 37 text

ࣝผࢠʹؔ͢Δཹҙࣄ߲ w ࣝผࢠ͸ඞͣӬଓԽΑΓ΋લʹఆ·ΔΑ͏ʹ͢Δ w 3%#ͷΦʔτΠϯΫϦϝϯτͳ஋Λࣝผࢠͱ͢ΔͱɺϨίʔυͷૠೖΛ͢ Δ·Ͱࣝผࢠ͕ఆ·Βͳ͍ӬଓԽͷλΠϛϯάͰ͔͠ΤϯςΟςΟΛ࡞ ੒Ͱ͖ͳ͍ w ଐੑͷதʹࣝผࢠͱͯ͠ػೳ͢Δ΋ͷʢྫ͑͹ϝʔϧΞυϨε͕શϢʔβ಺ ͰҰҙͰมߋ͞Εͳ͍ͳΒ֘౰͢Δʣ͕͋ΔͳΒͦΕΛ࠾༻ w ͦ͏Ͱͳ͍ͳΒ66*%Λ༻͍Δ

Slide 38

Slide 38 text

αʔϏε w ஋ΦϒδΣΫτ΍ΤϯςΟςΟʹॲཧΛ࣋ͨͤΔʹ͸ෆࣗવͳͱ͖ʹ༻͍ Δ w ؔ࿈͠ͳ͍஋ΦϒδΣΫτ΍ΤϯςΟςΟɺͦΕΒͷίϨΫγϣϯΛॲཧ͢ ΔͨΊʹ༻͍Δ w ͋·Γଟ༻͢ΔͱυϝΠϯϞσϧශ݂঱ʹؕΔ w ٕज़తৄࡉʹґଘ͢Δ৔߹ɺηύϨʔτΠϯλϑΣʔεʹ͢Δ

Slide 39

Slide 39 text

αʔϏεͷఆٛྫ trait NotifyTaskCreationService { def apply(task: Task): Unit } υϝΠϯϞσϧ͕ٻΊΔΠϯλϑΣʔεͷΈఆٛ

Slide 40

Slide 40 text

ϦϙδτϦ w ΤϯςΟςΟʢ·ͨ͸ͦΕΒΛͱΓ·ͱΊͨू໿ʣΛӬଓԽ͢Δ໾ׂ w ࣝผࢠʹΑΔऔΓग़͠Ҏ֎ʹઐ༻ͷΫΤϦ͕͋ͬͯ΋ߏΘͳ͍ w ΋Ζʹٕज़తৄࡉʹґଘ͢ΔͷͰɺαʔϏεͱಉ༷ʹηύϨʔτΠϯλ ϑΣʔεʹ͢Δ

Slide 41

Slide 41 text

ϦϙδτϦͷఆٛྫ trait Repository[ID, E <: Entity[ID], X] { def find(id: ID)(implicit context: X): Option[E] def store(entity: E)(implicit context: X): Unit } trait TaskRepository[X] extends Repository[TaskId, Task, X] { def findAllByCreatedAtRange( start: DateTime, end: DateTime )(implicit context: X): Seq[Task] }

Slide 42

Slide 42 text

ϦϙδτϦͷఆٛྫ trait Repository[ID, E <: Entity[ID], X] { def find(id: ID)(implicit context: X): Option[E] def store(entity: E)(implicit context: X): Unit } trait TaskRepository[X] extends Repository[TaskId, Task, X] { def findAllByCreatedAtRange( start: DateTime, end: DateTime )(implicit context: X): Seq[Task] } ֤ϦϙδτϦͷϕʔετϨΠτΛఆٛ *%ࣝผࢠͷܕ &ΤϯςΟςΟͷܕ 9ϦϙδτϦ༻ίϯςΩετͷܕ

Slide 43

Slide 43 text

ϦϙδτϦͷఆٛྫ trait Repository[ID, E <: Entity[ID], X] { def find(id: ID)(implicit context: X): Option[E] def store(entity: E)(implicit context: X): Unit } trait TaskRepository[X] extends Repository[TaskId, Task, X] { def findAllByCreatedAtRange( start: DateTime, end: DateTime )(implicit context: X): Seq[Task] } ֤ϦϙδτϦʹڞ௨ͷΠϯλϑΣʔεΛఆٛ

Slide 44

Slide 44 text

ϦϙδτϦͷఆٛྫ trait Repository[ID, E <: Entity[ID], X] { def find(id: ID)(implicit context: X): Option[E] def store(entity: E)(implicit context: X): Unit } trait TaskRepository[X] extends Repository[TaskId, Task, X] { def findAllByCreatedAtRange( start: DateTime, end: DateTime )(implicit context: X): Seq[Task] } ϕʔετϨΠτʹࣝผࢠͱΤϯςΟςΟͷܕΛ༩͑ͯܧঝ 9͸࣮૷ґଘͳͷͰ͜͜Ͱ͸ܾఆ͠ͳ͍

Slide 45

Slide 45 text

ϦϙδτϦͷఆٛྫ trait Repository[ID, E <: Entity[ID], X] { def find(id: ID)(implicit context: X): Option[E] def store(entity: E)(implicit context: X): Unit } trait TaskRepository[X] extends Repository[TaskId, Task, X] { def findAllByCreatedAtRange( start: DateTime, end: DateTime )(implicit context: X): Seq[Task] } ϦϙδτϦݻ༗ͷΫΤϦ͕͋Ε͹ϝιουͱͯ͠ఆٛ

Slide 46

Slide 46 text

%%%΁ͷऔΓ૊Έ w ࣮ફυϝΠϯۦಈઃܭʢ*%%%ʣΛνʔϜͰྠಡ͠ɺ%%%ͷ஌ࣝΛڞ༗ w िͷఆྫϛʔςΟϯάͰϢϏΩλεݴޠΛৼΓฦΓ w ͔͠͠༗༻ͳυϝΠϯϞσϧͷ֫ಘ͸·ͩ·ͩ೉͍͠ w ղܾ͢Δ໰୊΁ͷཧղ w ϞσϦϯά΁ͷཧղ w %%%΁ͷཧղ w ಉ࣌ʹίʔυϨϕϧͷઃܭ΋໛ࡧத

Slide 47

Slide 47 text

υϝΠϯͱ޲͖߹͍ͬͯ͘ w %%%ͱ޲͖߹͍͔ͬͯ͘͠ͳ͍ɻগͣͭ͠Ͱ΋औΓ૊ΊΔ w ౰વυϝΠϯʢղܾ͍ͨ͠໰୊ɺۀ຿ʣͱ΋޲͖߹͍ͬͯ͘ w %%%͸໨తͰ͸ͳ͘खஈɻϏδωε΁ͷߩݙ͕໨త

Slide 48

Slide 48 text

ΞϓϦέʔγϣϯ૚

Slide 49

Slide 49 text

ΞϓϦέʔγϣϯ૚ͷ໾ׂ w ΞϓϦέʔγϣϯ͕͍࣋ͬͯͳ͖Ό͍͚ͳ͍ৼ෣͍ͷఏڙ w υϝΠϯ૚ͷΦϒδΣΫτΛར༻ͯ͠ৼ෣͍Λ࣮ݱ w ͋͘·ͰΞϓϦέʔγϣϯͷৼ෣͍Ͱ͋Γɺ࣮ࡍͷ஌ࣝ΍ϧʔϧ͸υϝΠ ϯ૚ʹ͋ΔͨΊɺ͜ͷ૚͸ඇৗʹബ͘ͳΔɻ൓ରʹް͘ͳΔͱυϝΠϯ૚ ʹ͋Δ΂͖΋ͷ͕࿙Ε͍ͯΔલஹ w ඞཁʹԠͯ͡ηΩϡϦςΟ΍τϥϯβΫγϣϯͷ੍ޚΛߦ͏͜ͱ΋

Slide 50

Slide 50 text

ΞϓϦέʔγϣϯαʔϏεͷఆٛྫ class FinishTaskCommand(val id: TaskId) class FinishTaskApplicationService() { val taskRepo: TaskRepository[DBSession] = new JDBCTaskRepository() // TaskRepository[DBSession] の実装クラス def apply(command: FinishTaskCommand): Task = DB.localTx { implicit session => val task = taskRepo.find(command.id).getOrElse( throw new TaskNotFound(command.id) ) val finishedTask = task.finish() taskRepo.store(finishedTask) finishedTask } }

Slide 51

Slide 51 text

ΞϓϦέʔγϣϯαʔϏεͷఆٛྫ class FinishTaskCommand(val id: TaskId) class FinishTaskApplicationService() { val taskRepo: TaskRepository[DBSession] = new JDBCTaskRepository() // TaskRepository[DBSession] の実装クラス def apply(command: FinishTaskCommand): Task = DB.localTx { implicit session => val task = taskRepo.find(command.id).getOrElse( throw new TaskNotFound(command.id) ) val finishedTask = task.finish() taskRepo.store(finishedTask) finishedTask } } ΞϓϦέʔγϣϯαʔϏε΁ͷೖྗͱͳΔΫϥεΛఆٛ

Slide 52

Slide 52 text

ΞϓϦέʔγϣϯαʔϏεͷఆٛྫ class FinishTaskCommand(val id: TaskId) class FinishTaskApplicationService() { val taskRepo: TaskRepository[DBSession] = new JDBCTaskRepository() // TaskRepository[DBSession] の実装クラス def apply(command: FinishTaskCommand): Task = DB.localTx { implicit session => val task = taskRepo.find(command.id).getOrElse( throw new TaskNotFound(command.id) ) val finishedTask = task.finish() taskRepo.store(finishedTask) finishedTask } } ΞϓϦέʔγϣϯαʔϏεΛఆٛ

Slide 53

Slide 53 text

ΞϓϦέʔγϣϯαʔϏεͷఆٛྫ class FinishTaskCommand(val id: TaskId) class FinishTaskApplicationService() { val taskRepo: TaskRepository[DBSession] = new JDBCTaskRepository() // TaskRepository[DBSession] の実装クラス def apply(command: FinishTaskCommand): Task = DB.localTx { implicit session => val task = taskRepo.find(command.id).getOrElse( throw new TaskNotFound(command.id) ) val finishedTask = task.finish() taskRepo.store(finishedTask) finishedTask } } 'JOJTI5BTL$PNNBOEΛड͚औΓ5BTLΛฦ͢ϝιουΛఆٛ͠

Slide 54

Slide 54 text

ΞϓϦέʔγϣϯαʔϏεͷఆٛྫ class FinishTaskCommand(val id: TaskId) class FinishTaskApplicationService() { val taskRepo: TaskRepository[DBSession] = new JDBCTaskRepository() // TaskRepository[DBSession] の実装クラス def apply(command: FinishTaskCommand): Task = DB.localTx { implicit session => val task = taskRepo.find(command.id).getOrElse( throw new TaskNotFound(command.id) ) val finishedTask = task.finish() taskRepo.store(finishedTask) finishedTask } } τϥϯβΫγϣϯΛ։࢝͠

Slide 55

Slide 55 text

ΞϓϦέʔγϣϯαʔϏεͷఆٛྫ class FinishTaskCommand(val id: TaskId) class FinishTaskApplicationService() { val taskRepo: TaskRepository[DBSession] = new JDBCTaskRepository() // TaskRepository[DBSession] の実装クラス def apply(command: FinishTaskCommand): Task = DB.localTx { implicit session => val task = taskRepo.find(command.id).getOrElse( throw new TaskNotFound(command.id) ) val finishedTask = task.finish() taskRepo.store(finishedTask) finishedTask } } 5BTL3FQPTJUPSZ͔Βର৅ͷλεΫΛऔΓग़͠

Slide 56

Slide 56 text

ΞϓϦέʔγϣϯαʔϏεͷఆٛྫ class FinishTaskCommand(val id: TaskId) class FinishTaskApplicationService() { val taskRepo: TaskRepository[DBSession] = new JDBCTaskRepository() // TaskRepository[DBSession] の実装クラス def apply(command: FinishTaskCommand): Task = DB.localTx { implicit session => val task = taskRepo.find(command.id).getOrElse( throw new TaskNotFound(command.id) ) val finishedTask = task.finish() taskRepo.store(finishedTask) finishedTask } } ͦͷλεΫΛऴྃͤ͞

Slide 57

Slide 57 text

ΞϓϦέʔγϣϯαʔϏεͷఆٛྫ class FinishTaskCommand(val id: TaskId) class FinishTaskApplicationService() { val taskRepo: TaskRepository[DBSession] = new JDBCTaskRepository() // TaskRepository[DBSession] の実装クラス def apply(command: FinishTaskCommand): Task = DB.localTx { implicit session => val task = taskRepo.find(command.id).getOrElse( throw new TaskNotFound(command.id) ) val finishedTask = task.finish() taskRepo.store(finishedTask) finishedTask } } 5BTL3FQPTJUPSZΛ༻͍ͯλεΫͷมߋΛӬଓԽ͢Δ

Slide 58

Slide 58 text

ΞϓϦέʔγϣϯαʔϏεͷఆٛྫ class FinishTaskCommand(val id: TaskId) class FinishTaskApplicationService() { val taskRepo: TaskRepository[DBSession] = new JDBCTaskRepository() // TaskRepository[DBSession] の実装クラス def apply(command: FinishTaskCommand): Task = DB.localTx { implicit session => val task = taskRepo.find(command.id).getOrElse( throw new TaskNotFound(command.id) ) val finishedTask = task.finish() taskRepo.store(finishedTask) finishedTask } }

Slide 59

Slide 59 text

ΞϓϦέʔγϣϯαʔϏεͷఆٛྫ class FinishTaskCommand(val id: TaskId) class FinishTaskApplicationService() { val taskRepo: TaskRepository[DBSession] = new JDBCTaskRepository() // TaskRepository[DBSession] の実装クラス def apply(command: FinishTaskCommand): Task = DB.localTx { implicit session => val task = taskRepo.find(command.id).getOrElse( throw new TaskNotFound(command.id) ) val finishedTask = task.finish() taskRepo.store(finishedTask) finishedTask } } UBTL3FQPʹର࣮ͯ͠૷ΫϥεΛ୅ೖͯ͠͠·͍ͬͯΔ͍ͤͰɺΞϓϦ έʔγϣϯαʔϏεશମ͕ٕज़తৄࡉʹґଘɻ%*͠·͠ΐ͏

Slide 60

Slide 60 text

ίϚϯυͱΫΤϦ ΫΤϦ w σʔλΛࢀর͢Δ΋ͷ w σʔλΛมߋͯ͠͸͍͚ͳ͍ʢ$24ʣ w ࢀর͢Δ಺༰͸ΫϥΠΞϯτʹද ࣔ͢Δը໘ͷཁૉʹґଘ͢Δ ίϚϯυ w σʔλͳͲʹ࡞༻Λٴ΅͢΋ͷ w ʮσʔλ͕Ͳ͏มߋ͞ΕΔ͔ʯͱ ͍͏ͷ͸Ϗδωε্ͷ֓೦΍ϧʔ ϧʹଇΔ

Slide 61

Slide 61 text

ίϚϯυͱΫΤϦ ΫΤϦ w σʔλΛࢀর͢Δ΋ͷ w σʔλΛมߋͯ͠͸͍͚ͳ͍ʢ$24ʣ w ࢀর͢Δ಺༰͸ΫϥΠΞϯτʹද ࣔ͢Δը໘ͷཁૉʹґଘ͢Δ ίϚϯυ w σʔλͳͲʹ࡞༻Λٴ΅͢΋ͷ w ʮσʔλ͕Ͳ͏มߋ͞ΕΔ͔ʯͱ ͍͏ͷ͸Ϗδωε্ͷ֓೦΍ϧʔ ϧʹଇΔ ඞͣυϝΠϯΦϒδΣΫτΛར༻

Slide 62

Slide 62 text

ίϚϯυͱΫΤϦ ΫΤϦ w σʔλΛࢀর͢Δ΋ͷ w σʔλΛมߋͯ͠͸͍͚ͳ͍ʢ$24ʣ w ࢀর͢Δ಺༰͸ΫϥΠΞϯτʹද ࣔ͢Δը໘ͷཁૉʹґଘ͢Δ ίϚϯυ w σʔλͳͲʹ࡞༻Λٴ΅͢΋ͷ w ʮσʔλ͕Ͳ͏มߋ͞ΕΔ͔ʯͱ ͍͏ͷ͸Ϗδωε্ͷ֓೦΍ϧʔ ϧʹଇΔ ௚઀σʔλετΞ͔Βࢀর

Slide 63

Slide 63 text

ΫΤϦ༻ΞϓϦέʔγϣϯαʔϏεͷఆٛྫ class GetTaskStatisticsQuery() case class GetTaskStatisticsDto( numberOfTasks: Int, numberOfUnfinishedTasks: Int, numberOfFinishedTasks: Int ) class GetTaskStatisticsApplicationService() { def apply(query: GetTaskStatisticsQuery): GetTaskStatisticsDto = DB.readOnly { implicit session => sql"""SELECT COUNT(*), COUNT(finished_at) FROM tasks""".map { rs => val numberOfTasks = rs.int(1) val numberOfFinishedTasks = rs.int(2) GetTaskStatisticsDto( numberOfTasks, numberOfTasks - numberOfFinishedTasks, numberOfFinishedTasks ) }.single.apply.getOrElse(GetTaskStatisticsDto(0, 0, 0)) } }

Slide 64

Slide 64 text

ϓϨθϯςʔγϣϯ૚

Slide 65

Slide 65 text

ϓϨθϯςʔγϣϯ૚ͷ໾ׂ w ར༻ऀ͔ΒͷσʔλΛͲ͏ड͚औΓɺར༻ऀ΁Ͳ͏σʔλΛฦ͔͢ʹؔ৺ Λ࣋ͭɻར༻ऀͱͷ઀఺ w ΢Σϒ"1*Ͱݴ͏ͱ)551ͷϦΫΤετͷղऍ͓ΑͼϨεϙϯε΁ͷม׵͕ ֘౰ w ϦΫΤετΛղऍ͠ΞϓϦέʔγϣϯαʔϏε΁౉͢ w ΞϓϦέʔγϣϯαʔϏε͔Βͷ݁ՌΛϨεϙϯεʹม׵ w 4DBMBUSB KTPOT Λ࠾༻ʢ"LLB)551 DJSDF΁ͷ৐Γ׵͑΋ݕ౼தʣ

Slide 66

Slide 66 text

*OCPVOEͱ0VUCPVOE w ΞϓϦέʔγϣϯαʔϏε΁ͷೖྗํ๏ʢҾ਺ͷ਺ʣ͕౷Ұ͞Ε͍ͯΕ͹ɺ ػցతʹΞϓϦέʔγϣϯαʔϏεΛݺͼग़͢͜ͱ͕ग़དྷΔ w ͦͷͨΊʹೖྗ༻ΦϒδΣΫτʢ $PNNBOE  2VFSZʣΛ४උ w )551ϦΫΤετˠೖྗ༻ΦϒδΣΫτͷม׵Λ*OCPVOE w ΞϓϦέʔγϣϯαʔϏεग़ྗˠ)551Ϩεϙϯεͷม׵Λ0VUCPVOE

Slide 67

Slide 67 text

)551ϦΫΤετˠೖྗ༻ΦϒδΣΫτ POST /path/to/api HTTP/1.1 Content-Type: application/json ... { "id": "79062e11-6c96-4487-95f5-d3acf7dea808" } FinishTaskCommand( id = TaskId(79062e11-6c96-4487-95f5-d3acf7dea808) )

Slide 68

Slide 68 text

*OCPVOEͷఆٛྫ object FinishTaskInbound { private implicit val jsonFormats: Formats = DefaultFormats ++ Seq(...) case class Body(id: TaskId) def apply(request: ScalatraRequest): FinishTaskCommand = { val body = request.bodyAsJson.extract[Body] FinishTaskCommand(body.id) } }

Slide 69

Slide 69 text

object FinishTaskInbound { private implicit val jsonFormats: Formats = DefaultFormats ++ Seq(...) case class Body(id: TaskId) def apply(request: ScalatraRequest): FinishTaskCommand = { val body = request.bodyAsJson.extract[Body] FinishTaskCommand(body.id) } } *OCPVOEͷఆٛྫ 4DBMBUSB3FRVFTUʢ)551ϦΫΤετʣΛೖྗͱ͠ɺ 'JOJTI5BTL$PNNBOEʢೖྗ༻ΦϒδΣΫτʣΛग़ྗͱ͢Δ

Slide 70

Slide 70 text

object FinishTaskInbound { private implicit val jsonFormats: Formats = DefaultFormats ++ Seq(...) case class Body(id: TaskId) def apply(request: ScalatraRequest): FinishTaskCommand = { val body = request.bodyAsJson.extract[Body] FinishTaskCommand(body.id) } } *OCPVOEͷఆٛྫ 4DBMBUSB3FRVFTU͔Βೖྗ༻ΦϒδΣΫτʹඞཁͳ஋ΛऔΓग़͢

Slide 71

Slide 71 text

object FinishTaskInbound { private implicit val jsonFormats: Formats = DefaultFormats ++ Seq(...) case class Body(id: TaskId) def apply(request: ScalatraRequest): FinishTaskCommand = { val body = request.bodyAsJson.extract[Body] FinishTaskCommand(body.id) } } *OCPVOEͷఆٛྫ औΓग़ͨ͠஋Ͱ'JOJTI5BTL$PNNBOEΛ࡞੒

Slide 72

Slide 72 text

ΞϓϦέʔγϣϯαʔϏεग़ྗˠ)551Ϩεϙϯε HTTP/1.1 200 OK Content-Type: application/json ... { "id": "79062e11-6c96-4487-95f5-d3acf7dea808", "title": "a title", "createdAt": "2017-05-27T10:00:00+09:00", "finishedAt": "2017-05-27T14:50:00+09:00" } Task( id = TaskId(79062e11-6c96-4487-95f5-d3acf7dea808), title = TaskTitle(a title), createdAt = DateTime(2017-05-27T10:00:00+09:00), finishedAt = Some(DateTime(2017-05-27T14:50:00+09:00)) )

Slide 73

Slide 73 text

0VUCPVOEͷఆٛྫ object FinishTaskOutbound { case class Body( id: TaskId, title: TaskTitle, createdAt: DateTime, finishedAt: Option[DateTime] ) def apply(task: Task): ActionResult = { val body = Body( id = task.id, title = task.title, createdAt = task.createdAt, finishedAt = task.finishedAt ) Ok(body) } }

Slide 74

Slide 74 text

object FinishTaskOutbound { case class Body( id: TaskId, title: TaskTitle, createdAt: DateTime, finishedAt: Option[DateTime] ) def apply(task: Task): ActionResult = { val body = Body( id = task.id, title = task.title, createdAt = task.createdAt, finishedAt = task.finishedAt ) Ok(body) } } 0VUCPVOEͷఆٛྫ 5BTLʢ'JOJTI5BTL"QQMJDBUJPO4FSWJDFͷग़ྗʣΛೖྗͱ͠ɺ "DUJPO3FTVMUʢ4DBMBUSBʹ͓͚Δ)551ϨεϙϯεʣΛग़ྗͱ͢Δ

Slide 75

Slide 75 text

object FinishTaskOutbound { case class Body( id: TaskId, title: TaskTitle, createdAt: DateTime, finishedAt: Option[DateTime] ) def apply(task: Task): ActionResult = { val body = Body( id = task.id, title = task.title, createdAt = task.createdAt, finishedAt = task.finishedAt ) Ok(body) } } 0VUCPVOEͷఆٛྫ )551Ϩεϙϯεຊจͷ+40/༻ͷέʔεΫϥεΛ࡞੒

Slide 76

Slide 76 text

object FinishTaskOutbound { case class Body( id: TaskId, title: TaskTitle, createdAt: DateTime, finishedAt: Option[DateTime] ) def apply(task: Task): ActionResult = { val body = Body( id = task.id, title = task.title, createdAt = task.createdAt, finishedAt = task.finishedAt ) Ok(body) } } 0VUCPVOEͷఆٛྫ 0,ͳ"DUJPO3FTVMUΛ࡞੒

Slide 77

Slide 77 text

4DBMBUSBʹࡌͤΔ class Endpoints extends ScalatraServlet with JacksonJsonSupport { private implicit val formats: Formats = DefaultFormats ++ Seq(...) before { contentType = formats("json") } post("/FinishTask") { run(FinishTaskApplicationService, FinishTaskInbound, FinishTaskOutbound) } ... private def run(...): ActionResult = ... }

Slide 78

Slide 78 text

$POUSPMMFSͷྫ class FinishTaskController( applicationService: FinishTaskApplicationService, presenter: FinishTaskPresenter ) { private implicit val jsonFormats: Formats = DefaultFormats ++ Seq(...) case class Body(id: TaskId) def apply(request: ScalatraRequest): ActionResult = { val body = request.bodyAsJson.extract[Body] val user = applicationService(body.id) presenter(user) } }

Slide 79

Slide 79 text

3&45GVMͳ63-ઃܭ 63- ΞϓϦέʔγϣϯαʔϏε w (FU5BTL w $SFBUF5BTL w -PHJO w 4VN/VNCFST

Slide 80

Slide 80 text

3&45GVMͳ63-ઃܭ 63- w (&5UBTLT5"4,@*% w 1045UBTLT ΞϓϦέʔγϣϯαʔϏε w (FU5BTL w $SFBUF5BTL w -PHJO w 4VN/VNCFST

Slide 81

Slide 81 text

3&45GVMͳ63-ઃܭ 63- w (&5UBTLT5"4,@*% w 1045UBTLT w 1045TFTTJPO ͳΔ΄Ͳ ΞϓϦέʔγϣϯαʔϏε w (FU5BTL w $SFBUF5BTL w -PHJO w 4VN/VNCFST

Slide 82

Slide 82 text

3&45GVMͳ63-ઃܭ 63- w (&5UBTLT5"4,@*% w 1045UBTLT w 1045TFTTJPO ͳΔ΄Ͳ  w ΞϓϦέʔγϣϯαʔϏε w (FU5BTL w $SFBUF5BTL w -PHJO w 4VN/VNCFST

Slide 83

Slide 83 text

࣮ࡍʹ࠾༻͍ͯ͠Δ63-ઃܭ 63- w (&5(FU5BTL w 1045$SFBUF5BTL w (&5-PHJO w (&54VN/VNCFST ΞϓϦέʔγϣϯαʔϏε w (FU5BTL w $SFBUF5BTL w -PHJO w 4VN/VNCFST

Slide 84

Slide 84 text

΢Σϒ"1*ʹ͓͚Δ63-ઓུ w ܾͯ͠3&45GVM͕໾ʹཱͨͳ͍ͱ͍͏͜ͱͰ͸ͳ͍ w ΞϓϦͷͨΊͷ΢Σϒ"1*ͳΒ͹ɺΞϓϦͷϢʔεέʔεΛ࣮ݱ͢ΔͨΊʹ دΓఴͬͨ"1*ͱͳΔͨΊɺϢʔεέʔεΞϓϦέʔγϣϯαʔϏεͱ ͷ63-ͷํ͕౎߹͕ྑ͍ w αʔυύʔςΟʹఏڙ͢Δ΢Σϒ"1*ͳΒ͹ɺ޿͘ఏڙ͢ΔͨΊϢʔεέʔ εΛఆΊΒΕͳ͍ɻαʔϏε͕อ͍࣋ͯ͠ΔϦιʔεͷ$36%͚ͩΛఏڙ͠ɺ ࣗ༝ʹѻͬͯ΋Β͏ɻͦΕͳΒ3&45GVMͷํ͕౎߹͕ྑ͍

Slide 85

Slide 85 text

ΠϯϑϥετϥΫνϟ૚

Slide 86

Slide 86 text

ΠϯϑϥετϥΫνϟ૚ͷ໾ׂ w ٕज़తৄࡉΛఏڙ w σʔλετΞ w ϝʔϧૹ৴ w ϝοηʔδૹ৴ w FUD w υϝΠϯ૚ͳͲͰఆٛ͞ΕͨΠϯλϑΣʔεΛ࣮૷

Slide 87

Slide 87 text

࠶ܝϦϙδτϦͷఆٛྫ trait Repository[ID, E <: Entity[ID], X] { def find(id: ID)(implicit context: X): Option[E] def store(entity: E)(implicit context: X): Unit } trait TaskRepository[X] extends Repository[TaskId, Task, X] { def findAllByCreatedAtRange( start: DateTime, end: DateTime )(implicit context: X): Seq[Task] }

Slide 88

Slide 88 text

ϦϙδτϦ࣮૷ͷఆٛྫ class JDBCTaskRepository() extends TaskRepository[DBSession] { def find(id: TaskId)(implicit context: DBSession): Option[Task] = { ... } def store(task: Task)(implicit context: DBSession): Unit = { ... } def findAllByCreatedAtRange( start: DateTime, end: DateTime )(implicit context: DBSession): Seq[Task] = { ... } }

Slide 89

Slide 89 text

ϦϙδτϦ࣮૷ͷఆٛྫ class JDBCTaskRepository() extends TaskRepository[DBSession] { def find(id: TaskId)(implicit context: DBSession): Option[Task] = { ... } def store(task: Task)(implicit context: DBSession): Unit = { ... } def findAllByCreatedAtRange( start: DateTime, end: DateTime )(implicit context: DBSession): Seq[Task] = { ... } }

Slide 90

Slide 90 text

ϦϙδτϦ࣮૷ͷఆٛྫ class JDBCTaskRepository() extends TaskRepository[DBSession] { def find(id: TaskId)(implicit context: DBSession): Option[Task] = { ... } def store(task: Task)(implicit context: DBSession): Unit = { ... } def findAllByCreatedAtRange( start: DateTime, end: DateTime )(implicit context: DBSession): Seq[Task] = { ... } }

Slide 91

Slide 91 text

GJOEϝιουͷத਎ val t = TaskTable.syntax("t") withSQL { select .from(TaskTable as t) .where.eq(t.id, id) }.map { rs => val taskRecord = TaskRecord(t)(rs) taskRecord.toDomainObject }.single.apply

Slide 92

Slide 92 text

ͦͷଞ

Slide 93

Slide 93 text

Ϗϧυ w TCUΛ࢖༻ w ίʔυϑΥʔϚολͱͯ͠TCUTDBMBSJGPSNΛ࢖༻ w KBSʹ·ͱΊΔͨΊʹTCUBTTFNCMZΛ࢖༻ w ෳ਺ͷϓϩδΣΫτʹ෼ׂ

Slide 94

Slide 94 text

ෳ਺ͷϓϩδΣΫτʹ෼ׂυϝΠϯ lazy val domain = Project( id = "domain", base = file("domain"), settings = defaultSettings ++ Seq( libraryDependencies ++= Seq( // Joda-Timeなどの基本的なクラスを提供してくれるライブラリ ) ) )

Slide 95

Slide 95 text

ෳ਺ͷϓϩδΣΫτʹ෼ׂ࣮૷ lazy val jdbcImpl = Project( id = "jdbcImpl", base = file("jdbc_impl"), settings = defaultSettings ++ Seq( libraryDependencies ++= Seq( // ScalikeJDBCなどの実装に必要なライブラリ ) ) ).dependsOn(domain)

Slide 96

Slide 96 text

ෳ਺ͷϓϩδΣΫτʹ෼ׂΞϓϦέʔγϣϯ lazy val app = Project( id = "app", base = file("app"), settings = defaultSettings ++ Seq( libraryDependencies ++= Seq( // Scalatraなどのプレゼンテーションに必要なライブラリ ) ) ).dependsOn(domain, jdbcImpl, ...)

Slide 97

Slide 97 text

ςετ w 4DBMB5FTUΛ࢖༻ w ݱঢ়͸υϝΠϯΦϒδΣΫτͷςετ͓Αͼ&&ςετΛهड़ w ࣮૷ͷςετ͸͋ͬͨํ͕ྑ͍

Slide 98

Slide 98 text

એ఻ w גࣜձࣾϝσΟϩϜIUUQTNFEJSPNDPKQ͸։ൃऀΛืू͍ͯ͠·͢ w ։ൃͱͪΌΜͱ޲͖߹͍͍ͨํେ׻ܴ w 4DBMBͰαʔόαΠυ w 4XJGUͰJ04ΞϓϦ w +BWBʢ,PUMJO΋࢖͏͔΋ʁʣͰ"OESPJEΞϓϦ w +BWB4DSJQUʢ4DBMBKT΋࢖͏͔΋ʁʣͰ΢ΣϒΞϓϦ

Slide 99

Slide 99 text

࿩ͨ͜͠ͱ w ΞʔΩςΫνϟ w ϨΠϠʔυΞʔΩςΫνϟ w %*1 w υϝΠϯ૚ w ஋ΦϒδΣΫτ w ෆมͱଐੑʹΑΔ౳Ձ w ΤϯςΟςΟ w ࣝผࢠʹؔ͢Δཹҙࣄ߲ w αʔϏε w ϦϙδτϦ w %%%΁ͷऔΓ૊Έ w ΞϓϦέʔγϣϯ૚ w ΞϓϦέʔγϣϯαʔϏε w ίϚϯυͱΫΤϦ w ϓϨθϯςʔγϣϯ૚ w *OCPVOEͱ0VUCPVOE w 63-ઃܭ w ΠϯϑϥετϥΫνϟ૚ w ͦͷଞ w Ϗϧυ w ςετ