クラシコムとLaravelとDDD

5651249e8a50ba212fd8c19727479aac?s=47 Takeru Hirose
September 13, 2018

 クラシコムとLaravelとDDD

5651249e8a50ba212fd8c19727479aac?s=128

Takeru Hirose

September 13, 2018
Tweet

Transcript

  1. ኍ੉݈ʢגࣜձࣾΫϥγίϜʣ -BSBWFM.FFUVQ5PLZP7PM ΫϥγίϜͱ-BSBWFMͱ%%%

  2. ೥ɺѪ஌ݝੜ·Εɻ೥݄ɺגࣜձࣾΫϥγίϜʹೖࣾɻ લ৬·Ͱ͸3VCZPO3BJMTͰͷΞϓϦέʔγϣϯ։ൃɺσβΠϯ૊৫ ͷ্ཱͪ͛ͳͲʹܞΘΔɻݱࡏ͸-BSBWFMͰͷΞϓϦέʔγϣϯ։ൃ ͷ΄͔ɺσβΠφʔ࠾༻ʹऔΓ૊Ήɻ ኍ੉݈5BLFSV)JSPTF!UBLFSV

  3. w &$ ϝσΟΞͷΑ͏ͳαΠτ w ݄ؒ17໿ ສ w ݄ؒ66໿ສ w ࣾ಺Ͱ։ൃɾӡ༻

    ΫϥγίϜʮ๺Ԥɺ฻Β͠ͷಓ۩ళʯΛӡӦ IPLVPILVSBTIJDPN
  4. -BSBWFM %%%ʢΫϥγίϜͷ৔߹ʣ

  5. 3BJMT͔Β-BSBWFM΁ͷॻ͖׵͑ϓϩδΣΫτ ঎඼ϖʔδ Χʔτʢܾࡁʣ -BSBWFM %%%Λ࠾༻

  6. ۀ຿஌ࣝΛίʔυͰදݱ ʢ-BSBWFMʹͰ͖Δ͚ͩґଘ͠ͳ͍ʣ -BZFSFE"SDIJUFDUVSF 1SFTFOUBUJPO-BZFS *OGSBTUSVDUVSF-BZFS "QQMJDBUJPO-BZFS %PNBJO-BZFS -BSBWFMͷػೳΛ࠷େݶʹ׆༻

  7. w ϢϏΩλεݴޠΫϥεʢܕʣʢ&OUJUZ 7BMVF0CKFDU FUDʣ w ྫʣ"QQa%PNBJOa.PEFMTa6TFSa&OUJUZ w ֤Ϋϥε͸1MBJO0ME1)10CKFDU 1010 

    w &OUJUZͰ͋ͬͯ΋&MPRVFOUa.PEFMΛܧঝ͠ͳ͍ʢ&MPRVFOUͱ͸ผ෺ʣ w ίϯετϥΫλʹΑͬͯෆม৚݅ΛνΣοΫ͢Δ w ࢓༷ʹ൓͍ͯ͠Ε͹ྫ֎ʢΠϯελϯεΛ࡞Δ͜ͱ͕Ͱ͖ͳ͍ʣ ۀ຿஌ࣝʢυϝΠϯϩδοΫʣΛίʔυͰදݱ
  8. ྫʣ߹ܭֹۚͷܭࢉ ঎඼୯Ձ ஫จ਺ྔ খܭ ߹ܭ ഑ૹྉ

  9. ྫʣ߹ܭֹۚͷܭࢉ ঎඼୯Ձ Product\UnitPrice ஫จ਺ྔ Order\Quantity খܭ Order\SubTotal ߹ܭ Order\Total ഑ૹྉ

    Shipping\Fee
  10. declare(strict_types=1); final class Product\UnitPrice { public function __construct(int $value) {

    if ($value < 0) { throw new \InvalidArgumentException(); } $this->value = $value; } } ྫʣ঎඼୯Ձ WBMVFͷʮ঎඼୯Ձʯ͸࡞Εͳ͍ WBMVF͸ඞͣJOU
  11. declare(strict_types=1); final class Order\Quantity { public function __construct(int $value) {

    if ($value < 1) { throw new \InvalidArgumentException(); } $this->value = $value; } } ྫʣ஫จ਺ྔ WBMVFͷʮ஫จ਺ྔʯ͸࡞Εͳ͍ WBMVF͸ඞͣJOU
  12. declare(strict_types=1); final class Order\SubTotal { public function __construct( Product\UnitPrice $unitPrice,

    Order\Quantity $quantity ) { $this->value = $unitPrice->value() * $quantity->value(); } } ྫʣখܭ঎඼୯Ձ ஫จ਺ྔ ʮখܭʯ͸ඞͣʮ঎඼୯Ձʯͱʮ஫จ਺ྔʯ͔Β࡞ΒΕΔ
  13. declare(strict_types=1); final class Shipping\Method { public function calculateFee(Order\SubTotal $subTotal): Shipping\Fee

    { if ($subTotal->value() >= self::IS_FREE) { return new Shipping\Fee(0); } return new Shipping\Fee(self::REGULAR_FEE); } } ྫʣখܭ͕ҰఆֹۚҎ্ͷ৔߹͸഑ૹྉ͕ແྉ ඞͣʮখܭʯΛ༻͍ͯܭࢉ͞ΕΔ ඞͣʮ഑ૹྉʯΛฦ͢
  14. declare(strict_types=1); final class Order\Total { public function __construct( Shipping\Method $shippingMethod,

    Order\SubTotal $subTotal ) { $shippingFee = $shippingMethod->calculateFee($subTotal); $this->value = $subTotal->value() + $shippingFee->value(); } } ྫʣ߹ܭখܭ খܭΛجʹܭࢉ͞Εͨ഑ૹྉ ࢓༷Ҏ֎ͷํ๏Ͱʮ߹ܭʯΛ࡞Δ͜ͱ͕Ͱ͖ͳ͍
  15. w ۀ຿஌ࣝΛݴޠ࢓༷ʹΑͬͯදݱͰ͖Δʢڧ੍Ͱ͖Δʣ w Ҿ਺ɾฦΓ஋ͷܕࢦఆ͕ͦͷ··ͦͷ֓೦ͷ࢓༷ɾؔ܎ੑΛදݱ w ࢓༷ʹ൓͍ͯ͠Ε͹࣮ߦͰ͖ͳ͍˰όάͷ௿ݮɾૣظൃݟ w ࢓༷ʢϩδοΫʣ͕Ϋϥεʹ಺แ͞Ε͍ͯΔͷͰࢄҳ͠ͳ͍ w ফඅ੫ͱ͔ʜʢ੫ࠐՁ֨

    ਺ྔPS੫ൈՁ֨ ਺ྔ ੫཰ʣ w ࢓༷ʹ൓ͨ͠Πϯελϯε͕ଘࡏ͠ಘͳ͍ͷͰඞཁͳςετ΋ݮΔ ϢϏΩλεݴޠΫϥεʢܕʣ
  16. Ҿ਺ɾฦΓ஋ͷؒҧ͍˰5ZQF&SSPS ݴޠ࢓༷ʹΑͬͯදݱͰ͖Δͱ͍͏͜ͱ ࢓༷ʹ൓͢Δ৔߹˰-PHJD&YDFQUJPO ➔ྫ֎͕ى͖ͳ͍Α͏ʹ࣮૷͢Ε͹͍͍ͩͨେৎ෉ l͜ͷྨͷྫ֎͕ग़ͨ৔߹͸ɺࣗ෼͕ॻ͍ ͨίʔυΛमਖ਼͢΂͖Ͱ͢ɻz

  17. -BSBWFMͱ%%%ͷ౷߹

  18. %PNBJO-BZFS⾩*OGSBTUSVDUVSF-BZFS 1SFTFOUBUJPO-BZFS *OGSBTUSVDUVSF-BZFS "QQMJDBUJPO-BZFS %PNBJO-BZFS

  19. w 3FQPTJUPSZ1BUUFSO w &OUJUZࣗ਎͸ӬଓԽʹؔ͢ΔϝιουΛ࣋ͨͳ͍ w 3FQPTJUPSZ͔Βऔಘˠมߋˠ3FQPTJUPSZʹ౉͢͜ͱͰอଘ w 3FQPTJUPSZ಺Ͱ&MPRVFOU⾩&OUJUZΛ૬ޓม׵ w 3FQPTJUPSZ͕֎෦ͱ΍ΓͱΓ͢Δ஋͸%PNBJO-BZFSͷΫϥεʢܕʣ

    w &MPRVFOU͸03.ͩͱׂΓ੾ΔʢରͰରԠ͍ͯ͠Δͱ͸ݶΒͳ͍ʣ w 3FQPTJUPSZ&MPRVFOUʹͰ͖Δ͚ͩۀ຿஌ࣝΛ࣋ͨͤͳ͍ &OUJUZͷӬଓԽ
  20. declare(strict_types=1); final class UserRepository implements User\Repository { public function find(User\Id

    $id): User\Entity { $record = UserEloquent::find($id->value()); $entity = ...; return $entity; } public function store(User\Entity $entity): void { $record = ...; $record->save(); } } ྫʣ6TFS3FQPTJUPSZ JOUFSGBDF͸%PNBJO-BZFSʹ഑ஔˠ4FSWJDF1SPWJEFSʹొ࿥ &MPRVFOUˠ&OUJUZʹม׵ &OUJUZˠ&MPRVFOUʹม׵
  21. "QQMJDBUJPO-BZFS⾩%PNBJO-BZFS 1SFTFOUBUJPO-BZFS *OGSBTUSVDUVSF-BZFS "QQMJDBUJPO-BZFS %PNBJO-BZFS

  22. w $POUSPMMFSͷ໾ׂ͸6*ͱ%PNBJO-BZFSͷؒΛऔΓ࣋ͭ͜ͱ w Ϣʔβ͔ΒͷೖྗΛ%PNBJO-BZFSͷ֓೦ʹม׵͢Δ w %PNBJO-BZFSͷ֓೦ΛϢʔβ΁ͷग़ྗʹม׵͢Δ w 7BMJEBUPSͷ໾ׂ͸ʮྫ֎Λൃੜͤ͞ͳ͍͜ͱʯ w ෆਖ਼ͳೖྗΛϢʔβʹ෼͔Γ΍͘͢ϑΟʔυόοΫ͢Δ͜ͱʹूத͢Δ

    ʢσʔλͷ੔߹ੑ͸%PNBJO-BZFSҎԼʹΑͬͯ୲อ͞Ε͍ͯΔʣ w %PNBJO-BZFSΛʮ࢖͏ଆʯ͕ࣄલ৚݅ɾෆม৚݅Λຬͨٛ͢຿Λෛ͏
 ʢܖ໿ʹΑΔઃܭʣ $POUSPMMFS7BMJEBUPS
  23. declare(strict_types=1); class UsersController extends Controller { public function show(int $id)

    { $user = app(User\Repository::class)->find(new User\Id($id)); // [...] } public function store(StoreRequest $request) { $data = $request->validate(); $user = ...; app(User\Repository::class)->store($user); } } ྫʣ6TFST$POUSPMMFS "QQMJDBUJPO-BZFS͸%PNBJO-BZFSʹ഑ஔ͞ΕͨJOUFSGBDFʹґଘ͢Δ 7BMJEBUPSΛ௨աͨ͠஋ʹΑͬͯ&OUJUZΛੜ੒
  24. w -BSBWFMͷ͍͍ͨͯͷػೳ͸*OUFSGBDFΛ࣮૷͍ͯ͠Ε͹࢖͑Δ w Ϣʔβʔೝূʢ"VUIFOUJDBUJPO"VUIPSJ[BUJPOʣ͸6TFS.PEFM͕&MPRVFOU Ͱͳͯ͘΋࢖͑Δ w -BSBWFMʹ༻ҙ͞Ε͍ͯΔ֦ுͷ࢓૊ΈΛ࠷େݶʹ׆༻͢Δ w #MBEFͷ%JSFDUJWFΛ֦ு͢Ε͹WJFXʹ͓͍ͯ%PNBJO-BZFSͷΫϥεΛࣗ વʹ࢖͑Δ

    ͦͷଞ
  25. ΍ͬͯΈͯͲ͏͔ͩͬͨ

  26. w ۀ຿஌ࣝʹର͢Δཧղ͕ਂ·Δʢ෼͔Βͳ͍ͱ࡞Εͳ͍ʣ w ࣗ෼͕ϓϩδΣΫτʹೖͬͨͷ͸ೖࣾͯ͠ϲ݄ޙ͘Β͍ w Ҏલ͔Β͍ΔΤϯδχΞͱҰॹʹϞσϦϯάˠϞϒϓϩάϥϛϯά w ίʔυͰදݱ͠Α͏ͱ͢Δ͜ͱͰ࢓༷͕໌շʹͳΔ w ͢΂ͯͷ֓೦Λ࿦ཧతʹهड़͢ΔͨΊᐆດͳ࢓༷͕ଘࡏ͠ಘͳ͍

    w ࿦ཧతʹໃ६ͨ͠࢓༷͕ൃݟ͞Εͨ͜ͱ΋ w ίʔυΛಡΊ͹࢓༷͕෼͔Δˠߏஙޙ΋ۀ຿஌ࣝͷڞ༗͕༰қ ʮֶͼʯ͕൒୺ͳ͍
  27. ʮֶͼʯ͕൒୺ͳ͍ Ϟϒϓϩάϥϛϯά ϞσϦϯά

  28. w ۀ຿஌ࣝʢ࠷΋େࣄͰෳࡶͳ෦෼ʣʹؔ͢Δςετ͕γϯϓϧʹͳΔ w ୯७ͳςετͷੵΈॏͶʹΑͬͯ࢓༷͕कΒΕ͍ͯΔ͜ͱΛ୲อͰ͖Δ w པΓʹͳΔίʔυΧόϨοδɾ੩తղੳʢQIQTUBOʣ w ʮ࠷ѱͷࣄଶʯΛট͘ϦεΫΛ௿ݮͰ͖Δ w ݴޠ࢓༷ͷ੍໿ʹΑΓۀ຿஌͔ࣝΒҳ୤ͨ͠هड़͸࣮ߦͰ͖ͳ͍

    w ྫ֎͕ى͖ͳ͍Α͏ʹ࣮૷͢Ε͹͍͍ͩͨେৎ෉ʢ࠶ܝʣ ҆৺ײ͕൒୺ͳ͍
  29. ྫʣখܭΛςετ͢Δ৔߹ ঎඼୯Ձ Product\UnitPrice ஫จ਺ྔ Order\Quantity খܭ Order\SubTotal

  30. class ProductUnitPriceTest extends TestCase { public function testConstruct(): void {

    $expectedValue = $this->faker()->numberBetween(0); $unitPrice = new Product\UnitPrice($expectedValue); $this->assertEquals($expectedValue, $unitPrice->value()); } public function testConstructFail(): void { $this->expectException(\InvalidArgumentException::class); $invalidValue = $this->faker()->numberBetween(-2147483647, -1); new Product\UnitPrice($invalidValue); } } ྫʣ঎඼୯Ձͷςετ ਖ਼ৗܥʢWBMVFʣ ҟৗܥʢWBMVFʣ
  31. class OrderQuantityTest extends TestCase { public function testConstruct(): void {

    $expectedValue = $this->faker()->numberBetween(1); $quantity = new Order\Quantity($expectedValue); $this->assertEquals($expectedValue, $quantity->value()); } public function testConstructFail(): void { $this->expectException(\InvalidArgumentException::class); $invalidValue = $this->faker()->numberBetween(-2147483647, 0); new Order\Quantity($invalidValue); } } ྫʣ஫จ਺ྔͷςετ ਖ਼ৗܥʢWBMVFʣ ҟৗܥʢWBMVFʣ
  32. class OrderSubTotalTest extends TestCase { public function testConstruct(): void {

    $unitPrice = new Product\UnitPrice($this->faker()->numberBetween(0)); $quantity = new Order\Quantity($this->faker()->numberBetween(1)); $expectedValue = $unitPrice->value() * $quantity->value(); $subTotal = new Order\SubTotal($unitPrice, $quantity); $this->assertEquals($expectedValue, $subTotal->value()); } } ྫʣখܭͷςετ Ҿ਺ͱͳΔΦϒδΣΫτͷҟৗܥ͸ςετࡁΈ Ҿ਺ͷܕ͸ݴޠ࢓༷ʹΑͬͯอূ͞Ε͍ͯΔˠͨͩͷֻ͚ࢉͷςετ
  33. w ΄ͱΜͲͷ෼ذ͕୯७ w ˠ༰қʹ໢ཏͰ͖Δ w ˠ໢ཏͰ͖͍ͯΕ͹҆৺ w !DPWFSTΛͪΌΜͱॻ͘ • forceCoversAnnotation="true"

    པΓʹͳΔίʔυΧόϨοδ
  34. ҆৺ײ͕൒୺ͳ͍ ੩తղੳʢQIQTUBOʣ ΧόϨοδʢ$PWFSBMMTʣ

  35. w ϞσϦϯά೉͍͠ w Ϟσϧͷڥքͱ%#ͷτϥϯβΫγϣϯ΍ύϑΥʔϚϯεͱͷ݉Ͷ߹͍ w Ϟσϧͷ੔߹ੑͱ6*ͷॊೈੑͱͷ݉Ͷ߹͍ w ྫʣ഑ૹઌ͕ܾఆ͞Ε͍ͯͳ͍ͷʹ഑ૹྉΛද͍ࣔͨ͠ w ͦ΋ͦ΋-BSBWFMʢ1)1ʣͰ΍Δ΂͖ͩͬͨͷ͔ʁ

    w 1)1Ͱ΋ܕΛѻ͏ݴޠͱͯ͠͸·ͩ·ͩඇྗʢδΣωϦοΫͱ͔ʣ w ΍ͬͺΓ&MPRVFOUΛૉ௚ʹ࢖ͬͨ΄͏͕-BSBWFM͸׆͖Δ w -BSBWFMͷར఺ͷҰͭͰ͋Δ։ൃ଎౓͸Ͳ͏ͯ͠΋٘ਜ਼ʹͳΔ ൓ল఺ʢ΍ͬͯΈͯ෼͔ͬͨ͜ͱʣ
  36. w %%%͕ઃܭख๏ͱͯ͠༗༻ͳͷ͸͔͕֬ͩɺͲ͜·Ͱίʔυʹམͱ͠ ࠐΉ͔͸બ୒ͷ༨஍ʢ෯ʣ͕͋Δͱࢥ͏ w Ϣʔβʔʹ͍ۙ෦෼͸ૉૣ͘։ൃɾ൓෮͍ͨ͠ʢ-BSBWFMΒ͘͠࡞Γ͍ͨʣ w Ϗδωε্ͷཧ༝ʹΑΓ࢓༷ͱ6*͕ໃ६͢Δ͜ͱ͸Α͋͘Δ͜ͱ w %%%ͰखʹೖΔݎ࿚ੑɾอकੑ͸٘ਜ਼ʹͨ͘͠ͳ͍ w

    4P& 4ZTUFNPG&OHBHFNFOU 4P3 4ZTUFNPG3FDPSE ͱ͍͏੾ΓޱͰ ΞϓϦέʔγϣϯΛ෼ׂ͢Δͷ͸ΞϦ͔΋͠Εͳ͍ w 4P3తͳ෦෼͕ಷॏʹͳͬͯ΋͍͚ͳ͍ˠ.JDSPTFSWJDFT"SDIJUFDUVSF Ͳ͏͢Ε͹ྑ͍ͷͩΖ͏ʁ
  37. 4P&4P3ͱ͍͏੾ΓޱͰΞϓϦέʔγϣϯΛ෼ׂʁ "QQMJDBUJPO 4P& %PNBJO" 4P3 *OGSBTUSVDUVSF" %#֎෦"1* ૉૣ͍։ൃɾ൓෮ ݎ࿚ੑɾอकੑʢେ͖͘ͳΓ͗͢ͳ͍Α͏ʹ෼ׂʣ ಈతܕ෇͚ݴޠʁ

    ੩తܕ෇͚ݴޠʁ %PNBJO# 4P3
  38. ·ͱΊ

  39. w %%%ΛऔΓೖΕΔԸܙ͸େ͖͍ʢֶͼͱ҆৺ײʣ w ֦ுʹରͯ͠։͔Ε͍ͯΔͷ͸-BSBWFMͷྑ͍ͱ͜Ζ w ΞϓϦέʔγϣϯͷੑ࣭΍ߏ੒ɺݴޠɾ'8ͷಛੑΛؑΈͯɺऔΓೖ Εํ͸΋ͬͱߟ͍͖͍͑ͯͨ ·ͱΊ

  40. ΫϥγίϜͰ͸ΤϯδχΞɾσβΠφʔΛืू͍ͯ͠·͢ IUUQTXXXXBOUFEMZDPNDPNQBOJFTLVSBTIJDPN

  41. ͝ਗ਼ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠