Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Microservice within a Monolith #phpday
Search
Joop Lammerts
May 11, 2019
Programming
190
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Microservice within a Monolith #phpday
Joop Lammerts
May 11, 2019
More Decks by Joop Lammerts
See All by Joop Lammerts
_Rootnet__You_re_Agile_is_broken__and_here_is_how_to_fix_it.pdf
jlammerts
0
60
How to improve your team synergy w/The Attitude Model #DPC19
jlammerts
0
210
Microservice within a Monolith #devdays2019
jlammerts
0
93
Microservice within a Monolith v1
jlammerts
0
160
The Attitude Model
jlammerts
0
46
Improve your team synergy w/The Attitude model
jlammerts
0
400
Other Decks in Programming
See All in Programming
AGENTS.md Is Not Enough:Build Skills, Don't Download Them
lx_t
0
130
手動確認はもう限界 〜XCUITestでCustom URL Schemeの遷移を起動種別ごとに自動テストする〜 / Testing Custom URL Schemes with XCUITest
otouto
0
340
技術的負債を組織課題として解く-増えすぎたマイクロサービスとの戦い-
reimaru
1
2.3k
速く作れる。その次は、速く確かめられる開発へ 〜AIネイティブ開発を支える、Shift Down〜 / Can build fast. Next, moving to development where we can verify fast.
rkaga
6
4.6k
App Intentsのビルドプロセスを支える技術
kntkymt
0
430
テストを司るデーモンに会いに行く 〜隔離した仮想マシンでテストを通すまで〜
h1d3mun3
1
570
setup-vp GitLab対応の裏側
naokihaba
0
120
AI Agent時代のリアーキテクチャ戦略と実践
hokaccha
9
5k
ゲームコントローラやキーボードのファームウェアをSwiftで書く
kishikawakatsumi
1
250
[GoCon2026] When Goroutines Are Not Enough: Runtime Locality in High-Throughput Go
takehaya
6
2.5k
JAWS-UG 東京支部が始める、JAWS-UG支部コラボ / JAWS-UG lunchtime LT Collaboration
y0hgi
0
110
モジュールの視点からSwiftを読み解く #iosdc
s_shimotori
0
190
Featured
See All Featured
DBのスキルで生き残る技術 - AI時代におけるテーブル設計の勘所
soudai
PRO
68
58k
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
31
2.9k
Claude Code のすすめ
schroneko
67
230k
Odyssey Design
rkendrick25
PRO
2
820
How to make the Groovebox
asonas
2
2.5k
Git: the NoSQL Database
bkeepers
PRO
432
67k
Improving Core Web Vitals using Speculation Rules API
sergeychernyshev
21
1.6k
Deep Space Network (abreviated)
tonyrice
0
320
What Being in a Rock Band Can Teach Us About Real World SEO
427marketing
0
1.1k
Conquering PDFs: document understanding beyond plain text
inesmontani
PRO
4
3.1k
Bootstrapping a Software Product
garrettdimon
PRO
306
120k
GraphQLとの向き合い方2022年版
quramy
50
15k
Transcript
Microservices within a Monolith #phpday @jlammerts
Joop Lammerts Developer @procurios for +3 years @jlammerts
Procurios Cluster
Procurios Cluster for context
Our Monolith
Our monolith ~ backend: 3.000.000 lines of code distributed over
18.000 PHP files ~ frontend: 350.000 lines in 1800 JavaScript files 800.000 lines of CSS code
Usage
Usage • 2000 clients • 800.000 users • 500.000 visitors
an hour
None
Monolith
None
Microservices
Service #1 Service #2 Service #3
Microservices, or microservice architecture, is an approach to application development
in which a large application is built as a suite of modular components or services. Assumption
Microservices, or microservice architecture, is an approach to application development
in which a large application is built as a suite of modular components or services. Assumption
Modules
Modulair Monolith
Modulair Monolith • Bounded context with no dependencies on each
other • Information can be duplicated for each bounded context
None
What to do with your legacy Monolith?
Project |--- core |--- modules |--- cms |--- meeting |---
relation |--- user
Project |--- core |--- modules |--- cms |--- meeting ->
attendee -> meeting -> registration -> ticket |--- relation |--- user
final class RegistrationController { public function register() { $userId =
$_SESSION['userId']; $pdo = new \PDO('localhost'); $statement = $pdo->prepare(" SELECT * FROM `user` WHERE `id` = ? "); $statement->execute([$userId]); $userData = $statement->fetch()[0]; if (!$userData) { HttpResponse::redirect('/login'); } $form = $this->getRegistrationForm(); $data = $form->getData(); if (!$data['meetingId'] || !$data['ticketId'] || !$data['remark']) { return $form; } $statement = $pdo->prepare(" UPDATE `tickets` SET `sold` = 1 WHERE WHERE `id` = ? "); $statement->execute([ $data['ticketId'] ]); if ($statement->rowCount() !== 1) { return 'There are no tickets available'; } $statement = $pdo->prepare(" INSERT INTO `attendee` SET `user_id` = ?, `first_name` = ?, `last_name` = ?, `meeting_id` = ?, `ticket_id` = ?, `remark` = ?, "); $statement->execute([ $userData['id'], $userData['firstName'], $userData['name'], $data['meetingId'], $data['ticketId'], $data['remark'], ]); /* * send confirmation stuff */ \HttpResponse::redirect('/'); } }
namespace Meeting\Registration; final class RegistrationController { public function register() {
$userId = $_SESSION['userId']; $pdo = new \PDO('localhost'); $statement = $pdo->prepare(" SELECT * FROM `user` WHERE `id` = ? "); $statement->execute([$userId]); $userData = $statement->fetch()[0]; if (!$userData) { HttpResponse::redirect('/login'); } // }
namespace Meeting\Registration; final class RegistrationController { public function register() {
$user = UserService::getCurrentUser(); if (!$user->isAuthenticated()) { HttpResponse::redirect('/login'); } // }
namespace User; final class UserService { public static function getCurrentUser():
User { $userId = $_SESSION['userId'] ?? null; if ($userId === null) { return User::guest(); } $pdo = new \PDO('localhost'); $statement = $pdo->prepare(" SELECT * FROM `user` WHERE `id` = ? "); $statement->execute([$userId]); $userData = $statement->fetch()[0]; return $userData ? User::populate($userData); : User::guest(); }
User is now a bounded context
final class RegistrationController { public function register() { $user =
UserService::getCurrentUser(); if (!$user->isAuthenticated()) { HttpResponse::redirect('/login'); } $form = $this->getRegistrationForm(); $data = $form->getData(); if (!$data['meetingId'] || !$data['ticketId'] || !$data['remark']) { return $form; } $statement = $pdo->prepare(" UPDATE `tickets` SET `sold` = 1 WHERE WHERE `id` = ? "); $statement->execute([ $data['ticketId'] ]); if ($statement->rowCount() !== 1) { return 'There are no tickets available'; } $statement = $pdo->prepare(" INSERT INTO `attendee` SET `user_id` = ?, `first_name` = ?, `last_name` = ?, `meeting_id` = ?, `ticket_id` = ?, `remark` = ?, "); $statement->execute([ $userData['id'], $userData['firstName'], $userData['name'], $data['meetingId'], $data['ticketId'], $data['remark'], ]); /* * send confirmation stuff */ \HttpResponse::redirect('/'); } }
But wait, there is more!
public function register() { // $form = $this->getRegistrationForm(); $data =
$form->getData(); if (!$data['meetingId'] || !$data['ticketId'] || !$data['remark']) { return $form; } $statement = $pdo->prepare(" UPDATE `tickets` SET `sold` = 1 WHERE `id` = ? AND `sold` = 0 "); $statement->execute([ $data['ticketId'] ]); if ($statement->rowCount() !== 1) { return 'There are no tickets available'; } // }
public function register() { // $form = $this->getRegistrationForm(); $data =
$form->getData(); if (!$data['meetingId'] || !$data['ticketId'] || !$data['remark']) { return $form; } try { $ticket = TicketService::purchase($data['ticketId']); } catch (CouldNotPurchaseTicket $e) { return 'There are no tickets available'; } // }
final class TicketService { public static function purchase(int $ticketId): Ticket
{ $connection = DB::getConnection(); $statement = $connection->prepare(" UPDATE `tickets` SET `sold` = 1 WHERE `id` = ? AND `sold` = 0 "); $statement->execute([ $data['ticketId'] ]); if ($statement->rowCount() !== 1) { throw CouldNotPurchaseTicket::becauseNoTicketsLef(); } return new Ticket($ticketId); } }
public function register() { // $statement = $pdo->prepare(" INSERT INTO
`attendee` SET `user_id` = ?, `first_name` = ?, `last_name` = ?, `meeting_id` = ?, `ticket_id` = ?, `remark` = ?, "); $statement->execute([ $user->getId(), $user->getFirstName(), $user->getName(), $data['meetingId'], $data['ticketId'], $data['remark'], ]); // }
public function register() { // $attendee = new Attendee( $user->getId(),
$user->getFirstName(), $user->getName() ); RegistrationService::register($data['meetingId'], $attendee, $ticket, $data['remark']); /* * send confirmation stuff */ HttpResponse::redirect('/'); }
Modules sent messages
final class RegistrationService { public static function register(int $meetingId, Attendee
$attendee, Ticket $ticket, string $remark): void { $repository = self::getRepository(); $registration = $repository->create($meetingId, $attendee, $ticket, $remark); $registrationCreated = new RegistrationCreated($registration); foreach (self::getListenerProvider()->getListenersForEvent($registrationCreated) as $listener) { $listener->handle($registrationCreated); } } }
final class NotifyAttendee { public function handle(RegistrationCreated $registrationCreated): void {
// send confirmation stuff } }
final class RegistrationController { public function register() { $user =
UserService::getCurrentUser(); if (!$user->isAuthenticated()) { HttpResponse::redirect('/login'); } $form = $this->getRegistrationForm(); $data = $form->getData(); if (!$data['meetingId'] || !$data['ticketId'] || !$data['remark']) { return $form; } try { $ticket = TicketService::purchase($data['ticketId']); } catch (CouldNotPurchaseTicket $e) { return 'There are no tickets available'; } $attendee = new Attendee($user->getId(), $user->getFirstName(), $user->getName()); RegistrationService::register($data['meetingId'], $attendee, $ticket, $data['remark']); HttpResponse::redirect('/'); } }
Take aways Locate and isolate Bounded contexts and turn them
into modules Let the world know what changed in an Event Driven plugin architecture
Joop Lammerts Website: www.procurios.com Twitter: @jlammerts Feedback: https://joind.in/talk/7c6ed