Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
クラシコムとLaravelとDDD
Search
Takeru Hirose
September 13, 2018
Programming
9.3k
8
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
クラシコムとLaravelとDDD
Laravel Meetup Tokyo Vol.11
https://laravel-meetup-tokyo.connpass.com/event/93838/
Takeru Hirose
September 13, 2018
More Decks by Takeru Hirose
See All by Takeru Hirose
Rails と Laravel どちらを選ぶべきか? / Rails or Laravel
takeru0757
0
3.3k
開発・CI・運用におけるDocker戦略(クラシコムの場合)/ Dockerising Apps at Kurashicom
takeru0757
1
3.9k
SimpleとEasyは違う / Simple is not Easy
takeru0757
99
48k
クラウドワークスとデザインガイドライン
takeru0757
2
1.9k
ユーザーのためのデザイン。ユーザーのためのデザイン組織。
takeru0757
4
5.1k
デザイナーとデザイナーじゃない人でデザイン組織を作る
takeru0757
4
3.7k
受託会社とサービス運営会社におけるUXの考え方の違い
takeru0757
1
2.8k
Other Decks in Programming
See All in Programming
OS アップデート対応の取り組み方がもっと共有されてほしい
andpad
0
110
Prismを使った型安全な暗号化_関数型まつり2026
_fhhmm
0
110
そのテスト、説明できますか?~LWテスト戦略FW~のご紹介
nakahara
0
200
関数型プログラミングのメリットって何だろう?
wanko_it
0
170
使用 Meilisearch 建立新聞搜尋工具
johnroyer
0
140
えっ!!コードを読まずに開発を!?
hananouchi
0
190
信頼性について考えてみる(SRE NEXT 2026 miniLT)
hayama17
0
170
SREの積み重ねがAI駆動開発のガードレールになった ― 7つの実践/SRE Guardrails The 7
tomoyakitaura
8
4k
Embedded SREと共に達成した会員管理システムのAWS移行 - SRE NEXT 2026 ランチスポンサーセッション
niftycorp
PRO
1
2.4k
【やさしく解説 設計編・中級 #6】良いアーキテクチャとは ~ 一本の登り道の、行き先 ~
panda728
PRO
0
150
音楽のための関数型プログラミング言語mimiumにおける多段階計算の活用
tomoyanonymous
1
310
エンジニア向け会社紹介/Findy Company Profile
findyinc
6
360k
Featured
See All Featured
How to Align SEO within the Product Triangle To Get Buy-In & Support - #RIMC
aleyda
2
1.6k
brightonSEO & MeasureFest 2025 - Christian Goodrich - Winning strategies for Black Friday CRO & PPC
cargoodrich
3
750
Embracing the Ebb and Flow
colly
88
5.1k
Google's AI Overviews - The New Search
badams
0
1.1k
Building Better People: How to give real-time feedback that sticks.
wjessup
370
20k
Why Our Code Smells
bkeepers
PRO
340
58k
Optimising Largest Contentful Paint
csswizardry
37
3.8k
Why Your Marketing Sucks and What You Can Do About It - Sophie Logan
marketingsoph
0
230
So, you think you're a good person
axbom
PRO
2
2.1k
Primal Persuasion: How to Engage the Brain for Learning That Lasts
tmiket
0
390
End of SEO as We Know It (SMX Advanced Version)
ipullrank
3
4.3k
Collaborative Software Design: How to facilitate domain modelling decisions
baasie
1
260
Transcript
ኍ݈ʢגࣜձࣾΫϥγίϜʣ -BSBWFM.FFUVQ5PLZP7PM ΫϥγίϜͱ-BSBWFMͱ%%%
ɺѪݝੜ·Εɻ݄ɺגࣜձࣾΫϥγίϜʹೖࣾɻ લ৬·Ͱ3VCZPO3BJMTͰͷΞϓϦέʔγϣϯ։ൃɺσβΠϯ৫ ͷ্ཱͪ͛ͳͲʹܞΘΔɻݱࡏ-BSBWFMͰͷΞϓϦέʔγϣϯ։ൃ ͷ΄͔ɺσβΠφʔ࠾༻ʹऔΓΉɻ ኍ݈5BLFSV)JSPTF!UBLFSV
w &$ ϝσΟΞͷΑ͏ͳαΠτ w ݄ؒ17 ສ w ݄ؒ66ສ w ࣾͰ։ൃɾӡ༻
ΫϥγίϜʮԤɺΒ͠ͷಓ۩ళʯΛӡӦ IPLVPILVSBTIJDPN
-BSBWFM %%%ʢΫϥγίϜͷ߹ʣ
3BJMT͔Β-BSBWFMͷॻ͖͑ϓϩδΣΫτ ϖʔδ Χʔτʢܾࡁʣ -BSBWFM %%%Λ࠾༻
ۀࣝΛίʔυͰදݱ ʢ-BSBWFMʹͰ͖Δ͚ͩґଘ͠ͳ͍ʣ -BZFSFE"SDIJUFDUVSF 1SFTFOUBUJPO-BZFS *OGSBTUSVDUVSF-BZFS "QQMJDBUJPO-BZFS %PNBJO-BZFS -BSBWFMͷػೳΛ࠷େݶʹ׆༻
w ϢϏΩλεݴޠΫϥεʢܕʣʢ&OUJUZ 7BMVF0CKFDU FUDʣ w ྫʣ"QQa%PNBJOa.PEFMTa6TFSa&OUJUZ w ֤Ϋϥε1MBJO0ME1)10CKFDU 1010
w &OUJUZͰ͋ͬͯ&MPRVFOUa.PEFMΛܧঝ͠ͳ͍ʢ&MPRVFOUͱผʣ w ίϯετϥΫλʹΑͬͯෆม݅ΛνΣοΫ͢Δ w ༷ʹ͍ͯ͠Εྫ֎ʢΠϯελϯεΛ࡞Δ͜ͱ͕Ͱ͖ͳ͍ʣ ۀࣝʢυϝΠϯϩδοΫʣΛίʔυͰදݱ
ྫʣ߹ܭֹۚͷܭࢉ ୯Ձ จྔ খܭ ߹ܭ ૹྉ
ྫʣ߹ܭֹۚͷܭࢉ ୯Ձ Product\UnitPrice จྔ Order\Quantity খܭ Order\SubTotal ߹ܭ Order\Total ૹྉ
Shipping\Fee
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
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
declare(strict_types=1); final class Order\SubTotal { public function __construct( Product\UnitPrice $unitPrice,
Order\Quantity $quantity ) { $this->value = $unitPrice->value() * $quantity->value(); } } ྫʣখܭ୯Ձ จྔ ʮখܭʯඞͣʮ୯Ձʯͱʮจྔʯ͔Β࡞ΒΕΔ
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); } } ྫʣখܭ͕ҰఆֹۚҎ্ͷ߹ૹྉ͕ແྉ ඞͣʮখܭʯΛ༻͍ͯܭࢉ͞ΕΔ ඞͣʮૹྉʯΛฦ͢
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(); } } ྫʣ߹ܭখܭ খܭΛجʹܭࢉ͞Εͨૹྉ ༷Ҏ֎ͷํ๏Ͱʮ߹ܭʯΛ࡞Δ͜ͱ͕Ͱ͖ͳ͍
w ۀࣝΛݴޠ༷ʹΑͬͯදݱͰ͖Δʢڧ੍Ͱ͖Δʣ w ҾɾฦΓͷܕࢦఆ͕ͦͷ··ͦͷ֓೦ͷ༷ɾؔੑΛදݱ w ༷ʹ͍ͯ͠Ε࣮ߦͰ͖ͳ͍˰όάͷݮɾૣظൃݟ w ༷ʢϩδοΫʣ͕Ϋϥεʹแ͞Ε͍ͯΔͷͰࢄҳ͠ͳ͍ w ফඅ੫ͱ͔ʜʢ੫ࠐՁ֨
ྔPS੫ൈՁ֨ ྔ ੫ʣ w ༷ʹͨ͠Πϯελϯε͕ଘࡏ͠ಘͳ͍ͷͰඞཁͳςετݮΔ ϢϏΩλεݴޠΫϥεʢܕʣ
ҾɾฦΓͷؒҧ͍˰5ZQF&SSPS ݴޠ༷ʹΑͬͯදݱͰ͖Δͱ͍͏͜ͱ ༷ʹ͢Δ߹˰-PHJD&YDFQUJPO ➔ྫ֎͕ى͖ͳ͍Α͏ʹ࣮͢Ε͍͍ͩͨେৎ l͜ͷྨͷྫ֎͕ग़ͨ߹ɺ͕ࣗॻ͍ ͨίʔυΛमਖ਼͖͢Ͱ͢ɻz
-BSBWFMͱ%%%ͷ౷߹
%PNBJO-BZFS⾩*OGSBTUSVDUVSF-BZFS 1SFTFOUBUJPO-BZFS *OGSBTUSVDUVSF-BZFS "QQMJDBUJPO-BZFS %PNBJO-BZFS
w 3FQPTJUPSZ1BUUFSO w &OUJUZࣗӬଓԽʹؔ͢ΔϝιουΛ࣋ͨͳ͍ w 3FQPTJUPSZ͔Βऔಘˠมߋˠ3FQPTJUPSZʹ͢͜ͱͰอଘ w 3FQPTJUPSZͰ&MPRVFOU⾩&OUJUZΛ૬ޓม w 3FQPTJUPSZ͕֎෦ͱΓͱΓ͢Δ%PNBJO-BZFSͷΫϥεʢܕʣ
w &MPRVFOU03.ͩͱׂΓΔʢରͰରԠ͍ͯ͠ΔͱݶΒͳ͍ʣ w 3FQPTJUPSZ&MPRVFOUʹͰ͖Δ͚ͩۀࣝΛ࣋ͨͤͳ͍ &OUJUZͷӬଓԽ
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ʹม
"QQMJDBUJPO-BZFS⾩%PNBJO-BZFS 1SFTFOUBUJPO-BZFS *OGSBTUSVDUVSF-BZFS "QQMJDBUJPO-BZFS %PNBJO-BZFS
w $POUSPMMFSͷׂ6*ͱ%PNBJO-BZFSͷؒΛऔΓ࣋ͭ͜ͱ w Ϣʔβ͔ΒͷೖྗΛ%PNBJO-BZFSͷ֓೦ʹม͢Δ w %PNBJO-BZFSͷ֓೦ΛϢʔβͷग़ྗʹม͢Δ w 7BMJEBUPSͷׂʮྫ֎Λൃੜͤ͞ͳ͍͜ͱʯ w ෆਖ਼ͳೖྗΛϢʔβʹ͔Γ͘͢ϑΟʔυόοΫ͢Δ͜ͱʹूத͢Δ
ʢσʔλͷ߹ੑ%PNBJO-BZFSҎԼʹΑͬͯ୲อ͞Ε͍ͯΔʣ w %PNBJO-BZFSΛʮ͏ଆʯ͕ࣄલ݅ɾෆม݅Λຬͨٛ͢Λෛ͏ ʢܖʹΑΔઃܭʣ $POUSPMMFS7BMJEBUPS
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Λੜ
w -BSBWFMͷ͍͍ͨͯͷػೳ*OUFSGBDFΛ࣮͍ͯ͠Ε͑Δ w Ϣʔβʔೝূʢ"VUIFOUJDBUJPO"VUIPSJ[BUJPOʣ6TFS.PEFM͕&MPRVFOU Ͱͳͯ͑͘Δ w -BSBWFMʹ༻ҙ͞Ε͍ͯΔ֦ுͷΈΛ࠷େݶʹ׆༻͢Δ w #MBEFͷ%JSFDUJWFΛ֦ு͢ΕWJFXʹ͓͍ͯ%PNBJO-BZFSͷΫϥεΛࣗ વʹ͑Δ
ͦͷଞ
ͬͯΈͯͲ͏͔ͩͬͨ
w ۀࣝʹର͢Δཧղ͕ਂ·Δʢ͔Βͳ͍ͱ࡞Εͳ͍ʣ w ͕ࣗϓϩδΣΫτʹೖͬͨͷೖࣾͯ͠ϲ݄ޙ͘Β͍ w Ҏલ͔Β͍ΔΤϯδχΞͱҰॹʹϞσϦϯάˠϞϒϓϩάϥϛϯά w ίʔυͰදݱ͠Α͏ͱ͢Δ͜ͱͰ༷͕໌շʹͳΔ w ͯ͢ͷ֓೦Λཧతʹهड़͢ΔͨΊᐆດͳ༷͕ଘࡏ͠ಘͳ͍
w ཧతʹໃ६༷͕ͨ͠ൃݟ͞Εͨ͜ͱ w ίʔυΛಡΊ༷͕͔Δˠߏஙޙۀࣝͷڞ༗͕༰қ ʮֶͼʯ͕ͳ͍
ʮֶͼʯ͕ͳ͍ Ϟϒϓϩάϥϛϯά ϞσϦϯά
w ۀࣝʢ࠷େࣄͰෳࡶͳ෦ʣʹؔ͢Δςετ͕γϯϓϧʹͳΔ w ୯७ͳςετͷੵΈॏͶʹΑ༷͕ͬͯकΒΕ͍ͯΔ͜ͱΛ୲อͰ͖Δ w པΓʹͳΔίʔυΧόϨοδɾ੩తղੳʢQIQTUBOʣ w ʮ࠷ѱͷࣄଶʯΛট͘ϦεΫΛݮͰ͖Δ w ݴޠ༷ͷ੍ʹΑΓۀ͔ࣝΒҳͨ͠هड़࣮ߦͰ͖ͳ͍
w ྫ֎͕ى͖ͳ͍Α͏ʹ࣮͢Ε͍͍ͩͨେৎʢ࠶ܝʣ ҆৺ײ͕ͳ͍
ྫʣখܭΛςετ͢Δ߹ ୯Ձ Product\UnitPrice จྔ Order\Quantity খܭ Order\SubTotal
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ʣ
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ʣ
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()); } } ྫʣখܭͷςετ ҾͱͳΔΦϒδΣΫτͷҟৗܥςετࡁΈ Ҿͷܕݴޠ༷ʹΑͬͯอূ͞Ε͍ͯΔˠͨͩͷֻ͚ࢉͷςετ
w ΄ͱΜͲͷذ͕୯७ w ˠ༰қʹཏͰ͖Δ w ˠཏͰ͖͍ͯΕ҆৺ w !DPWFSTΛͪΌΜͱॻ͘ • forceCoversAnnotation="true"
པΓʹͳΔίʔυΧόϨοδ
҆৺ײ͕ͳ͍ ੩తղੳʢQIQTUBOʣ ΧόϨοδʢ$PWFSBMMTʣ
w ϞσϦϯά͍͠ w Ϟσϧͷڥքͱ%#ͷτϥϯβΫγϣϯύϑΥʔϚϯεͱͷ݉Ͷ߹͍ w Ϟσϧͷ߹ੑͱ6*ͷॊೈੑͱͷ݉Ͷ߹͍ w ྫʣૹઌ͕ܾఆ͞Ε͍ͯͳ͍ͷʹૹྉΛද͍ࣔͨ͠ w ͦͦ-BSBWFMʢ1)1ʣͰΔ͖ͩͬͨͷ͔ʁ
w 1)1ͰܕΛѻ͏ݴޠͱͯ͠·ͩ·ͩඇྗʢδΣωϦοΫͱ͔ʣ w ͬͺΓ&MPRVFOUΛૉʹͬͨ΄͏͕-BSBWFM׆͖Δ w -BSBWFMͷརͷҰͭͰ͋Δ։ൃͲ͏ͯ٘͠ਜ਼ʹͳΔ লʢͬͯΈ͔ͯͬͨ͜ͱʣ
w %%%͕ઃܭख๏ͱͯ͠༗༻ͳͷ͔͕֬ͩɺͲ͜·Ͱίʔυʹམͱ͠ ࠐΉ͔બͷ༨ʢ෯ʣ͕͋Δͱࢥ͏ w Ϣʔβʔʹ͍ۙ෦ૉૣ͘։ൃɾ෮͍ͨ͠ʢ-BSBWFMΒ͘͠࡞Γ͍ͨʣ w Ϗδωε্ͷཧ༝ʹΑΓ༷ͱ6*͕ໃ६͢Δ͜ͱΑ͋͘Δ͜ͱ w %%%ͰखʹೖΔݎ࿚ੑɾอकੑ٘ਜ਼ʹͨ͘͠ͳ͍ w
4P& 4ZTUFNPG&OHBHFNFOU 4P3 4ZTUFNPG3FDPSE ͱ͍͏ΓޱͰ ΞϓϦέʔγϣϯΛׂ͢ΔͷΞϦ͔͠Εͳ͍ w 4P3తͳ෦͕ಷॏʹͳ͍͚ͬͯͳ͍ˠ.JDSPTFSWJDFT"SDIJUFDUVSF Ͳ͏͢Εྑ͍ͷͩΖ͏ʁ
4P&4P3ͱ͍͏ΓޱͰΞϓϦέʔγϣϯΛׂʁ "QQMJDBUJPO 4P& %PNBJO" 4P3 *OGSBTUSVDUVSF" %#֎෦"1* ૉૣ͍։ൃɾ෮ ݎ࿚ੑɾอकੑʢେ͖͘ͳΓ͗͢ͳ͍Α͏ʹׂʣ ಈతܕ͚ݴޠʁ
੩తܕ͚ݴޠʁ %PNBJO# 4P3
·ͱΊ
w %%%ΛऔΓೖΕΔԸܙେ͖͍ʢֶͼͱ҆৺ײʣ w ֦ுʹରͯ͠։͔Ε͍ͯΔͷ-BSBWFMͷྑ͍ͱ͜Ζ w ΞϓϦέʔγϣϯͷੑ࣭ߏɺݴޠɾ'8ͷಛੑΛؑΈͯɺऔΓೖ Εํͬͱߟ͍͖͍͑ͯͨ ·ͱΊ
ΫϥγίϜͰΤϯδχΞɾσβΠφʔΛืू͍ͯ͠·͢ IUUQTXXXXBOUFEMZDPNDPNQBOJFTLVSBTIJDPN
͝ਗ਼ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠