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
7
8.9k
クラシコムとLaravelとDDD
Laravel Meetup Tokyo Vol.11
https://laravel-meetup-tokyo.connpass.com/event/93838/
Takeru Hirose
September 13, 2018
Tweet
Share
More Decks by Takeru Hirose
See All by Takeru Hirose
Rails と Laravel どちらを選ぶべきか? / Rails or Laravel
takeru0757
0
3.1k
開発・CI・運用におけるDocker戦略(クラシコムの場合)/ Dockerising Apps at Kurashicom
takeru0757
1
3.6k
SimpleとEasyは違う / Simple is not Easy
takeru0757
94
44k
クラウドワークスとデザインガイドライン
takeru0757
2
1.6k
ユーザーのためのデザイン。ユーザーのためのデザイン組織。
takeru0757
4
4.6k
デザイナーとデザイナーじゃない人でデザイン組織を作る
takeru0757
4
3.5k
受託会社とサービス運営会社におけるUXの考え方の違い
takeru0757
1
2.5k
Other Decks in Programming
See All in Programming
テストコード書いてみませんか?
onopon
2
280
Fixstars高速化コンテスト2024準優勝解法
eijirou
0
160
ある日突然あなたが管理しているサーバーにDDoSが来たらどうなるでしょう?知ってるようで何も知らなかったDDoS攻撃と対策 #phpcon.2024
akase244
2
7.6k
「とりあえず動く」コードはよい、「読みやすい」コードはもっとよい / Code that 'just works' is good, but code that is 'readable' is even better.
mkmk884
6
1.3k
Go の GC の不得意な部分を克服したい
taiyow
3
960
Findy Team+ Awardを受賞したかった!ベストプラクティス応募内容をふりかえり、開発生産性向上もふりかえる / Findy Team Plus Award BestPractice and DPE Retrospective 2024
honyanya
0
130
Compose UIテストを使った統合テスト
hiroaki404
0
120
traP の部内 ISUCON とそれを支えるポータル / PISCON Portal
ikura_hamu
0
110
rails newと同時に型を書く
aki19035vc
4
570
オニオンアーキテクチャを使って、 Unityと.NETでコードを共有する
soi013
0
340
為你自己學 Python
eddie
0
500
PHPで作るWebSocketサーバー ~リアクティブなアプリケーションを知るために~ / WebSocket Server in PHP - To know reactive applications
seike460
PRO
2
720
Featured
See All Featured
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
132
33k
The Power of CSS Pseudo Elements
geoffreycrofte
74
5.4k
Git: the NoSQL Database
bkeepers
PRO
427
64k
Raft: Consensus for Rubyists
vanstee
137
6.7k
The Cost Of JavaScript in 2023
addyosmani
46
7.1k
Documentation Writing (for coders)
carmenintech
67
4.5k
It's Worth the Effort
3n
183
28k
How GitHub (no longer) Works
holman
312
140k
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
171
50k
Producing Creativity
orderedlist
PRO
343
39k
Designing for Performance
lara
604
68k
Creating an realtime collaboration tool: Agile Flush - .NET Oxford
marcduiker
26
1.9k
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
͝ਗ਼ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠