Slide 1

Slide 1 text

RESTLESS MICROSERVICES

Slide 2

Slide 2 text

RESTLESS MICROSERVICES with

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

No content

Slide 6

Slide 6 text

WE ARE HIRING!

Slide 7

Slide 7 text

RESTLESS MICROSERVICES

Slide 8

Slide 8 text

RESTLESS MICROSERVICES with

Slide 9

Slide 9 text

No content

Slide 10

Slide 10 text

No content

Slide 11

Slide 11 text

Billing

Slide 12

Slide 12 text

Billing Profile

Slide 13

Slide 13 text

Billing Profile Upload songs

Slide 14

Slide 14 text

Billing Search / buy music Profile Upload songs

Slide 15

Slide 15 text

Billing Search / buy music Profile Upload songs

Slide 16

Slide 16 text

bin public src templates config billing marketplace profile upload Billing Search / buy music Profile Upload songs

Slide 17

Slide 17 text

bin public src templates config marketplace profile upload Billing Search / buy music Profile Upload songs billing

Slide 18

Slide 18 text

bin public src templates config marketplace profile upload billing

Slide 19

Slide 19 text

bin public src templates config marketplace profile upload billing

Slide 20

Slide 20 text

bin public src templates config marketplace profile upload billing

Slide 21

Slide 21 text

No content

Slide 22

Slide 22 text

Search / buy music Upload songs Billing Profile

Slide 23

Slide 23 text

Search / buy music Upload songs Billing Profile

Slide 24

Slide 24 text

Search / buy music Upload songs Billing Profile

Slide 25

Slide 25 text

Search / buy music Upload songs Billing Profile

Slide 26

Slide 26 text

Search / buy music Upload songs Billing Profile

Slide 27

Slide 27 text

Search / buy music Upload songs Billing Profile

Slide 28

Slide 28 text

Search / buy music Upload songs Billing Profile

Slide 29

Slide 29 text

Search / buy music Upload songs Billing Profile

Slide 30

Slide 30 text

Search / buy music Upload songs Billing Profile

Slide 31

Slide 31 text

Search / buy music Upload songs Billing Profile

Slide 32

Slide 32 text

Should I use microservices?

Slide 33

Slide 33 text

What problems do they solve? Should I use microservices?

Slide 34

Slide 34 text

Noback, M (2017): “Microservices for everyone”, p3 Splitting one big software solution into multiple smaller ones will make it easier to cut away bad parts, to integrate new parts, and to run experiments, at infrastructure and code level. This entails a higher speed of change than what we normally experience when working on a monolithic application.

Slide 35

Slide 35 text

Search / buy music Upload songs Billing Profile

Slide 36

Slide 36 text

Search / buy music Upload songs Billing Profile

Slide 37

Slide 37 text

With a large, monolithic service, we have to scale everything together. […] if that behaviour is locked up in a giant monolithic application, we have to handle scaling everything as a piece. With smaller services, we can just scale those services that need scaling, allowing us to run other parts of the system on smaller, less powerful hardware. Newman, S (2015): “Building Microservices”, p5

Slide 38

Slide 38 text

Search / buy music Upload songs Billing Profile

Slide 39

Slide 39 text

Search / buy music Upload songs Billing Profile

Slide 40

Slide 40 text

Search / buy music Upload songs Billing Profile

Slide 41

Slide 41 text

Wolff, E (2016): “Microservices”, p57 A failure in the deployment of a single Microservice [doesn’t] impact the system as a whole.

Slide 42

Slide 42 text

Search / buy music Upload songs Billing Profile

Slide 43

Slide 43 text

Search / buy music Upload songs Billing Profile

Slide 44

Slide 44 text

Search / buy music Upload songs Billing Profile

Slide 45

Slide 45 text

What problems do they solve? Should I use microservices?

Slide 46

Slide 46 text

What problems do they solve? What new problems do they introduce? Should I use microservices?

Slide 47

Slide 47 text

Wolff, E (2016): “Microservices”, p72 With a Deployment Monolith it is relatively straightforward to monitor the system. When problems arise, the administrator can log into the system [and] analyse errors. Microservice based systems contain so many systems that this approach is no longer feasible. Consequently, there has to be a monitoring system that brings monitoring information from all the services together.

Slide 48

Slide 48 text

Search / buy music Upload songs Billing Profile

Slide 49

Slide 49 text

Search / buy music Upload songs Billing Profile

Slide 50

Slide 50 text

Search / buy music Upload songs Billing Profile

Slide 51

Slide 51 text

Newman, S (2015): “Building Microservices”, p5 […] we need to understand the new sources of failure that distributed systems have to deal with. Networks can and will fail, as will machines.

Slide 52

Slide 52 text

Search / buy music Upload songs Billing Profile

Slide 53

Slide 53 text

Search / buy music Upload songs Billing Profile

Slide 54

Slide 54 text

What problems do they solve? What new problems do they introduce? Should I use microservices?

Slide 55

Slide 55 text

What problems do they solve? What new problems do they introduce? Should I stick to a monolith? Should I use microservices?

Slide 56

Slide 56 text

No content

Slide 57

Slide 57 text

No content

Slide 58

Slide 58 text

No content

Slide 59

Slide 59 text

No content

Slide 60

Slide 60 text

No content

Slide 61

Slide 61 text

No content

Slide 62

Slide 62 text

Search / buy music Upload songs Billing Profile

Slide 63

Slide 63 text

Search / buy music Upload songs Billing Profile { "id": "9541df33-2077-499e-a6f3-579eec03cd0c", "eventType": "invoice", "value": "100" } JSON over HTTP

Slide 64

Slide 64 text

No content

Slide 65

Slide 65 text

Fidao, C (2014): https://fideloper.com/hexagonal-architecture

Slide 66

Slide 66 text

Fidao, C (2014): https://fideloper.com/hexagonal-architecture

Slide 67

Slide 67 text

Fidao, C (2014): https://fideloper.com/hexagonal-architecture

Slide 68

Slide 68 text

Fidao, C (2014): https://fideloper.com/hexagonal-architecture

Slide 69

Slide 69 text

Fidao, C (2014): https://fideloper.com/hexagonal-architecture

Slide 70

Slide 70 text

Fidao, C (2014): https://fideloper.com/hexagonal-architecture

Slide 71

Slide 71 text

Fidao, C (2014): https://fideloper.com/hexagonal-architecture

Slide 72

Slide 72 text

Fidao, C (2014): https://fideloper.com/hexagonal-architecture

Slide 73

Slide 73 text

No content

Slide 74

Slide 74 text

No content

Slide 75

Slide 75 text

No content

Slide 76

Slide 76 text

WE ARE HIRING!

Slide 77

Slide 77 text

Fidao, C (2014): https://fideloper.com/hexagonal-architecture

Slide 78

Slide 78 text

No content

Slide 79

Slide 79 text

No content

Slide 80

Slide 80 text

No content

Slide 81

Slide 81 text

No content

Slide 82

Slide 82 text

No content

Slide 83

Slide 83 text

No content

Slide 84

Slide 84 text

No content

Slide 85

Slide 85 text

No content

Slide 86

Slide 86 text

marketplace upload billing profile

Slide 87

Slide 87 text

marketplace upload billing profile bin public src config bin public src config bin public src config bin public src config templates

Slide 88

Slide 88 text

marketplace upload billing profile bin public src config bin public src config bin public src config bin public src config templates { "id": "9541df33-2077-499e-a6f3-579eec03cd0c", "eventType": "invoice", "value": "100" } JSON over HTTP

Slide 89

Slide 89 text

marketplace upload billing profile bin public src config bin public src config bin public src config bin public src config templates

Slide 90

Slide 90 text

marketplace upload billing profile

Slide 91

Slide 91 text

marketplace upload billing profile

Slide 92

Slide 92 text

bin public src templates config billing marketplace profile upload

Slide 93

Slide 93 text

No content

Slide 94

Slide 94 text

bin public src templates config billing marketplace profile upload

Slide 95

Slide 95 text

bin public src templates config billing marketplace profile upload

Slide 96

Slide 96 text

No content

Slide 97

Slide 97 text

No content

Slide 98

Slide 98 text

No content

Slide 99

Slide 99 text

$ composer require acme/billing-package

Slide 100

Slide 100 text

No content

Slide 101

Slide 101 text

{ "name": "acme/billing-package", "description": "Handles billing for things in our application", "version": "0.0.1", "license": "proprietary", "require": { "php": ">=7.3" }, "require-dev": { "phpunit/phpunit": "^8" }, "config": { "bin-dir": "bin" }, "autoload": { "psr-4": { "Acme\\Package\\Billing\\": "src/" } }, "autoload-dev": { "psr-4": { "Tests\\": "tests/" } } } composer.json

Slide 102

Slide 102 text

{ "name": "acme/billing-package", "description": "Handles billing for things in our application", "version": "0.0.1", "license": "proprietary", "require": { "php": ">=7.3" }, "require-dev": { "phpunit/phpunit": "^8" }, "config": { "bin-dir": "bin" }, "autoload": { "psr-4": { "Acme\\Package\\Billing\\": "src/" } }, "autoload-dev": { "psr-4": { "Tests\\": "tests/" } } } composer.json

Slide 103

Slide 103 text

composer.json { "name": "acme/billing-package", "description": "Handles billing for things in our application", "version": "0.0.1", "license": "proprietary", "require": { "php": ">=7.3" }, "require-dev": { "phpunit/phpunit": "^8" }, "config": { "bin-dir": "bin" }, "autoload": { "psr-4": { "Acme\\Package\\Billing\\": "src/" } }, "autoload-dev": { "psr-4": { "Tests\\": "tests/" } } }

Slide 104

Slide 104 text

src composer.json tests CardPayment.php CustomerRepository.php PaymentProcessor.php paymentProcessor = $paymentProcessor; $this->repository = $repository; } public function chargeCard(int $customerId, int $amountInPounds): void { $customer = $this->repository->find($customerId); if (null === $customer) { throw new \Exception('Customer not found'); } $this->paymentProcessor->debitAccount( $customer, $amountInPounds ); } public function listPayments(int $customerId): array { // ... }

Slide 105

Slide 105 text

src composer.json tests CardPayment.php CustomerRepository.php PaymentProcessor.php paymentProcessor = $paymentProcessor; $this->repository = $repository; } public function chargeCard(int $customerId, int $amountInPounds): void { $customer = $this->repository->find($customerId); if (null === $customer) { throw new \Exception('Customer not found'); } $this->paymentProcessor->debitAccount( $customer, $amountInPounds ); } public function listPayments(int $customerId): array { // ... }

Slide 106

Slide 106 text

src composer.json tests CardPayment.php CustomerRepository.php PaymentProcessor.php paymentProcessor = $paymentProcessor; $this->repository = $repository; } public function chargeCard(int $customerId, int $amountInPounds): void { $customer = $this->repository->find($customerId); if (null === $customer) { throw new \Exception('Customer not found'); } $this->paymentProcessor->debitAccount( $customer, $amountInPounds ); } public function listPayments(int $customerId): array { // ... }

Slide 107

Slide 107 text

src composer.json tests CardPayment.php CustomerRepository.php PaymentProcessor.php paymentProcessor = $paymentProcessor; $this->repository = $repository; } public function chargeCard(int $customerId, int $amountInPounds): void { $customer = $this->repository->find($customerId); if (null === $customer) { throw new \Exception('Customer not found'); } $this->paymentProcessor->debitAccount( $customer, $amountInPounds ); } public function listPayments(int $customerId): array { // ... }

Slide 108

Slide 108 text

src composer.json tests CardPayment.php CustomerRepository.php PaymentProcessor.php paymentProcessor = $paymentProcessor; $this->repository = $repository; } public function chargeCard(int $customerId, int $amountInPounds): void { $customer = $this->repository->find($customerId); if (null === $customer) { throw new \Exception('Customer not found'); } $this->paymentProcessor->debitAccount( $customer, $amountInPounds ); } public function listPayments(int $customerId): array { // ... }

Slide 109

Slide 109 text

Slide 110

Slide 110 text

src composer.json tests CardPayment.php CustomerRepository.php PaymentProcessor.php

Slide 111

Slide 111 text

src composer.json tests CardPayment.php CustomerRepository.php PaymentProcessor.php CardPaymentTest.php processor = $this->createMock(PaymentProcessor::class); $this->repository = $this->createMock(CustomerRepository::class); $this->cardPayment = new CardPayment($this->processor,$this->repository); } public function test_a_card_is_charged_the_correct_amount(): void { $customer = new Customer(); // ... $this->cardPayment->chargeCard($customer->getId(), 100); } public function test_an_exception_is_thrown_when_customer_is_not_found(): void { // ... } // ... }

Slide 112

Slide 112 text

processor = $this->createMock(PaymentProcessor::class); $this->repository = $this->createMock(CustomerRepository::class); $this->cardPayment = new CardPayment($this->processor,$this->repository); } public function test_a_card_is_charged_the_correct_amount(): void { $customer = new Customer(); // ... $this->cardPayment->chargeCard($customer->getId(), 100); } public function test_an_exception_is_thrown_when_customer_is_not_found(): void { // ... } // ... } src composer.json tests CardPayment.php CustomerRepository.php PaymentProcessor.php CardPaymentTest.php

Slide 113

Slide 113 text

No content

Slide 114

Slide 114 text

No content

Slide 115

Slide 115 text

$ composer require acme/billing-package

Slide 116

Slide 116 text

$ composer require acme/...

Slide 117

Slide 117 text

bin public src config vendor acme billing-package profile-package upload-package

Slide 118

Slide 118 text

bin public src config vendor acme billing-package profile-package upload-package adapter PaymentProcessorAdapter.php stripeApiKey = $stripeApiKey; } public function debitAccount(Customer $customer, int $amount): void { \Stripe\Stripe::setApiKey($this->stripeApiKey); \Stripe\Charge::create([ "amount" => $amount, "currency" => "gbp", "source" => $customer->getAuthToken() ]); } public function fetchTransactions(Customer $customer): array { // ... } }

Slide 119

Slide 119 text

bin public src config adapter PaymentProcessorAdapter.php vendor acme billing-package profile-package upload-package stripeApiKey = $stripeApiKey; } public function debitAccount(Customer $customer, int $amount): void { \Stripe\Stripe::setApiKey($this->stripeApiKey); \Stripe\Charge::create([ "amount" => $amount, "currency" => "gbp", "source" => $customer->getAuthToken() ]); } public function fetchTransactions(Customer $customer): array { // ... } }

Slide 120

Slide 120 text

No content

Slide 121

Slide 121 text

bin public src config adapter PaymentProcessorAdapter.php vendor acme billing-package profile-package upload-package stripeApiKey = $stripeApiKey; } public function debitAccount(Customer $customer, int $amount): void { \Stripe\Stripe::setApiKey($this->stripeApiKey); \Stripe\Charge::create([ "amount" => $amount, "currency" => "gbp", "source" => $customer->getAuthToken() ]); } public function fetchTransactions(Customer $customer): array { // ... } }

Slide 122

Slide 122 text

Search / buy music Upload songs Billing Profile

Slide 123

Slide 123 text

Search / buy music Upload songs Billing Profile Admin

Slide 124

Slide 124 text

Search / buy music Upload songs Billing Profile Admin

Slide 125

Slide 125 text

No content

Slide 126

Slide 126 text

{ "name": "acme/billing-bridge", "description": "Handles the infrastructure for the billing package", "version": "0.0.1", "license": "proprietary", "require": { "php": ">=7.3", "ext-PDO": "*", "ext-json": "*", "acme/billing-package": "*@dev", "symfony/config": ">=2.8,<3.5", "symfony/http-kernel": ">=2.8,<3.5", "symfony/dependency-injection": "<3.5" }, "require-dev": { "phpunit/phpunit": "^8" }, "autoload": { "psr-4": { "Acme\\Bridge\\Billing\\": "./src" } }, "autoload-dev": { "files": [ "tests/AppKernel.php" ] } } composer.json

Slide 127

Slide 127 text

{ "name": "acme/billing-bridge", "description": "Handles the infrastructure for the billing package", "version": "0.0.1", "license": "proprietary", "require": { "php": ">=7.3", "ext-PDO": "*", "ext-json": "*", "acme/billing-package": "*@dev", "symfony/config": ">=2.8,<3.5", "symfony/http-kernel": ">=2.8,<3.5", "symfony/dependency-injection": "<3.5" }, "require-dev": { "phpunit/phpunit": "^8" }, "autoload": { "psr-4": { "Acme\\Bridge\\Billing\\": "./src" } }, "autoload-dev": { "files": [ "tests/AppKernel.php" ] } } composer.json

Slide 128

Slide 128 text

{ "name": "acme/billing-bridge", "description": "Handles the infrastructure for the billing package", "version": "0.0.1", "license": "proprietary", "require": { "php": ">=7.3", "ext-PDO": "*", "ext-json": "*", "acme/billing-package": "*@dev", "symfony/config": ">=2.8,<3.5", "symfony/http-kernel": ">=2.8,<3.5", "symfony/dependency-injection": "<3.5" }, "require-dev": { "phpunit/phpunit": "^8" }, "autoload": { "psr-4": { "Acme\\Bridge\\Billing\\": "./src" } }, "autoload-dev": { "files": [ "tests/AppKernel.php" ] } } composer.json

Slide 129

Slide 129 text

{ "name": "acme/billing-bridge", "description": "Handles the infrastructure for the billing package", "version": "0.0.1", "license": "proprietary", "require": { "php": ">=7.3", "ext-PDO": "*", "ext-json": "*", "acme/billing-package": "*@dev", "symfony/config": ">=2.8,<3.5", "symfony/http-kernel": ">=2.8,<3.5", "symfony/dependency-injection": "<3.5" }, "require-dev": { "phpunit/phpunit": "^8" }, "autoload": { "psr-4": { "Acme\\Bridge\\Billing\\": "./src" } }, "autoload-dev": { "files": [ "tests/AppKernel.php" ] } } composer.json

Slide 130

Slide 130 text

{ "name": "acme/billing-bridge", "description": "Handles the infrastructure for the billing package", "version": "0.0.1", "license": "proprietary", "require": { "php": ">=7.3", "ext-PDO": "*", "ext-json": "*", "acme/billing-package": "*@dev", "symfony/config": ">=2.8,<3.5", "symfony/http-kernel": ">=2.8,<3.5", "symfony/dependency-injection": "<3.5" }, "require-dev": { "phpunit/phpunit": "^8" }, "autoload": { "psr-4": { "Acme\\Bridge\\Billing\\": "./src" } }, "autoload-dev": { "files": [ "tests/AppKernel.php" ] } } composer.json

Slide 131

Slide 131 text

{ "name": "acme/billing-bridge", "description": "Handles the infrastructure for the billing package", "version": "0.0.1", "license": "proprietary", "require": { "php": ">=7.3", "ext-PDO": "*", "ext-json": "*", "acme/billing-package": "*@dev", "symfony/config": ">=2.8,<3.5", "symfony/http-kernel": ">=2.8,<3.5", "symfony/dependency-injection": "<3.5" }, "require-dev": { "phpunit/phpunit": "^8" }, "autoload": { "psr-4": { "Acme\\Bridge\\Billing\\": "./src" } }, "autoload-dev": { "files": [ "tests/AppKernel.php" ] } } composer.json

Slide 132

Slide 132 text

src DependencyInjection BillingBridgeExtension.php PaymentProcessor Resources Config services.xml composer.json tests AppKernel.php root('billing_bridge'); $rootNode ->children() ->arrayNode('services') ->isRequired() ->children() ->scalarNode('pdo_connection') ->isRequired() ->cannotBeEmpty() ->end() ->end() ->end() ->arrayNode('parameters') ->isRequired() ->children() ->scalarNode('payment_provider_key') ->isRequired() ->cannotBeEmpty() ->end() ->end() ->end() ->end(); Configuration.php StripePaymentProcessor.php

Slide 133

Slide 133 text

src DependencyInjection BillingBridgeExtension.php PaymentProcessor Resources Config services.xml composer.json tests AppKernel.php Configuration.php root('billing_bridge'); $rootNode ->children() ->arrayNode('services') ->isRequired() ->children() ->scalarNode('pdo_connection') ->isRequired() ->cannotBeEmpty() ->end() ->end() ->end() ->arrayNode('parameters') ->isRequired() ->children() ->scalarNode('payment_provider_key') ->isRequired() ->cannotBeEmpty() ->end() ->end() ->end() ->end(); StripePaymentProcessor.php

Slide 134

Slide 134 text

src DependencyInjection BillingBridgeExtension.php PaymentProcessor Resources Config services.xml composer.json tests AppKernel.php Configuration.php root('billing_bridge'); $rootNode ->children() ->arrayNode('services') ->isRequired() ->children() ->scalarNode('pdo_connection') ->isRequired() ->cannotBeEmpty() ->end() ->end() ->end() ->arrayNode('parameters') ->isRequired() ->children() ->scalarNode('payment_provider_key') ->isRequired() ->cannotBeEmpty() ->end() ->end() ->end() ->end(); StripePaymentProcessor.php

Slide 135

Slide 135 text

root('billing_bridge'); $rootNode ->children() ->arrayNode('services') ->isRequired() ->children() ->scalarNode('pdo_connection') ->isRequired() ->cannotBeEmpty() ->end() ->end() ->end() ->arrayNode('parameters') ->isRequired() ->children() ->scalarNode('payment_provider_key') ->isRequired() ->cannotBeEmpty() ->end() ->end() ->end() ->end(); src DependencyInjection BillingBridgeExtension.php PaymentProcessor Resources Config services.xml composer.json tests AppKernel.php Configuration.php StripePaymentProcessor.php

Slide 136

Slide 136 text

src DependencyInjection BillingBridgeExtension.php PaymentProcessor Resources Config services.xml composer.json tests AppKernel.php Configuration.php processConfiguration(new Configuration(), $configs); $loader = new Loader\XmlFileLoader( $container, new FileLocator(__DIR__ . '/../Resources/config') ); $container->setAlias( 'billing_bridge.pdo_connection', $config['services']['pdo_connection'] ); $container->setAlias( 'billing_bridge.payment_provider_key', $config['parameters']['payment_provider_key'] ); $loader->load('services.xml'); } } StripePaymentProcessor.php

Slide 137

Slide 137 text

src DependencyInjection BillingBridgeExtension.php PaymentProcessor Resources Config services.xml composer.json tests AppKernel.php Configuration.php processConfiguration(new Configuration(), $configs); $loader = new Loader\XmlFileLoader( $container, new FileLocator(__DIR__ . '/../Resources/config') ); $container->setAlias( 'billing_bridge.pdo_connection', $config['services']['pdo_connection'] ); $container->setAlias( 'billing_bridge.payment_provider_key', $config['parameters']['payment_provider_key'] ); $loader->load('services.xml'); } } StripePaymentProcessor.php

Slide 138

Slide 138 text

src DependencyInjection BillingBridgeExtension.php PaymentProcessor Resources Config services.xml composer.json tests AppKernel.php Configuration.php processConfiguration(new Configuration(), $configs); $loader = new Loader\XmlFileLoader( $container, new FileLocator(__DIR__ . '/../Resources/config') ); $container->setAlias( 'billing_bridge.pdo_connection', $config['services']['pdo_connection'] ); $container->setAlias( 'billing_bridge.payment_provider_key', $config['parameters']['payment_provider_key'] ); $loader->load('services.xml'); } } StripePaymentProcessor.php

Slide 139

Slide 139 text

src DependencyInjection BillingBridgeExtension.php PaymentProcessor StripePaymentProcessor.php Resources Config services.xml composer.json tests AppKernel.php Configuration.php stripeApiKey = $stripeApiKey; } public function debitAccount(Customer $customer, int $amount): void { \Stripe\Stripe::setApiKey($this->stripeApiKey); \Stripe\Charge::create([ "amount" => $amount, "currency" => "gbp", "source" => $customer->getAuthToken() ]); } public function fetchTransactions(Customer $customer): array { // ... } }

Slide 140

Slide 140 text

src DependencyInjection BillingBridgeExtension.php PaymentProcessor StripePaymentProcessor.php Resources Config services.xml composer.json tests AppKernel.php Configuration.php stripeApiKey = $stripeApiKey; } public function debitAccount(Customer $customer, int $amount): void { \Stripe\Stripe::setApiKey($this->stripeApiKey); \Stripe\Charge::create([ "amount" => $amount, "currency" => "gbp", "source" => $customer->getAuthToken() ]); } public function fetchTransactions(Customer $customer): array { // ... } }

Slide 141

Slide 141 text

src DependencyInjection BillingBridgeExtension.php PaymentProcessor StripePaymentProcessor.php Resources Config services.xml composer.json tests AppKernel.php Configuration.php stripeApiKey = $stripeApiKey; } public function debitAccount(Customer $customer, int $amount): void { // ... } public function fetchTransactions(Customer $customer): array { \Stripe\Stripe::setApiKey($this->stripeApiKey); $list = \Stripe\Charge::all([ "customer" => $customer->getAuthToken() ]); return array_map(function ($payment) { return new PaymentDto($payment['name'], $payment['amount']); }, $list); } }

Slide 142

Slide 142 text

src DependencyInjection BillingBridgeExtension.php PaymentProcessor StripePaymentProcessor.php Resources Config services.xml composer.json tests AppKernel.php Configuration.php stripeApiKey = $stripeApiKey; } public function debitAccount(Customer $customer, int $amount): void { // ... } public function fetchTransactions(Customer $customer): array { \Stripe\Stripe::setApiKey($this->stripeApiKey); $list = \Stripe\Charge::all([ "customer" => $customer->getAuthToken() ]); return array_map(function ($payment) { return new PaymentDto($payment['name'], $payment['amount']); }, $list); } }

Slide 143

Slide 143 text

connection = $connection; } public function find(int $customerId): Customer { $query = $this->connection ->prepare('SELECT name, token FROM customer_accounts WHERE id = :id'); $query->bindValue(':id', $customerId); $result = $query->execute(); $customer = $result->fetchAll(\PDO::FETCH_ASSOC); return new Customer($customer[0]['name'], $customer[0]['token']); } } src DependencyInjection BillingBridgeExtension.php PaymentProcessor StripePaymentProcessor.php Resources Config services.xml tests AppKernel.php Configuration.php Repository PdoCustomerRepository.php

Slide 144

Slide 144 text

connection = $connection; } public function find(int $customerId): Customer { $query = $this->connection ->prepare('SELECT name, token FROM customer_accounts WHERE id = :id'); $query->bindValue(':id', $customerId); $result = $query->execute(); $customer = $result->fetchAll(\PDO::FETCH_ASSOC); return new Customer($customer[0]['name'], $customer[0]['token']); } } src DependencyInjection BillingBridgeExtension.php PaymentProcessor Resources Config services.xml tests AppKernel.php Configuration.php Repository PdoCustomerRepository.php StripePaymentProcessor.php

Slide 145

Slide 145 text

connection = $connection; } public function find(int $customerId): Customer { $query = $this->connection ->prepare('SELECT name, token FROM customer_accounts WHERE id = :id'); $query->bindValue(':id', $customerId); $result = $query->execute(); $customer = $result->fetchAll(\PDO::FETCH_ASSOC); return new Customer($customer[0]['name'], $customer[0]['token']); } } src DependencyInjection BillingBridgeExtension.php PaymentProcessor Resources Config services.xml tests AppKernel.php Configuration.php Repository PdoCustomerRepository.php StripePaymentProcessor.php

Slide 146

Slide 146 text

%billing_bridge.payment_provider_key% src DependencyInjection PaymentProcessor Configuration.php BillingBridgeExtension.php Resources Config services.xml tests AppKernel.php Repository PdoCustomerRepository.php StripePaymentProcessor.php

Slide 147

Slide 147 text

%billing_bridge.payment_provider_key% src DependencyInjection PaymentProcessor Configuration.php BillingBridgeExtension.php Resources Config services.xml tests AppKernel.php Repository PdoCustomerRepository.php StripePaymentProcessor.php

Slide 148

Slide 148 text

%billing_bridge.payment_provider_key% src DependencyInjection PaymentProcessor Configuration.php BillingBridgeExtension.php Resources Config services.xml tests AppKernel.php Repository PdoCustomerRepository.php StripePaymentProcessor.php

Slide 149

Slide 149 text

src DependencyInjection PaymentProcessor Configuration.php BillingBridgeExtension.php Resources Config services.xml tests AppKernel.php Repository PdoCustomerRepository.php StripePaymentProcessor.php %billing_bridge.payment_provider_key%

Slide 150

Slide 150 text

src DependencyInjection PaymentProcessor Configuration.php BillingBridgeExtension.php Resources Config services.xml tests AppKernel.php Repository PdoCustomerRepository.php StripePaymentProcessor.php %billing_bridge.payment_provider_key%

Slide 151

Slide 151 text

No content

Slide 152

Slide 152 text

$ composer require acme/billing-bridge

Slide 153

Slide 153 text

app config config.yml billing_bridge: services: pdo_connection: doctrine.dbal.billing_connection parameters: payment_provider_key: '%env(stripe_secret_key)%'

Slide 154

Slide 154 text

app config config.yml src Controller MarketplaceController.php container ->get('acme.billing.card_payment') ->debitAccount($customerId, $amount); } public function listChargesAction($customerId): Response { // ... $charges = $this->container ->get('acme.billing.card_payment') ->listPayments($customerId); return new Response(\json_encode($charges)); } }

Slide 155

Slide 155 text

No content

Slide 156

Slide 156 text

No content

Slide 157

Slide 157 text

Domain Objects

Slide 158

Slide 158 text

Domain Objects Scalars / JSON

Slide 159

Slide 159 text

Domain Objects Scalars / JSON

Slide 160

Slide 160 text

Domain Objects Scalars / JSON

Slide 161

Slide 161 text

Domain Objects Scalars / JSON

Slide 162

Slide 162 text

Domain Objects Scalars / JSON

Slide 163

Slide 163 text

No content

Slide 164

Slide 164 text

No content

Slide 165

Slide 165 text

Unit tests Integration tests E2E tests

Slide 166

Slide 166 text

No content

Slide 167

Slide 167 text

No content

Slide 168

Slide 168 text

No content

Slide 169

Slide 169 text

No content

Slide 170

Slide 170 text

No content

Slide 171

Slide 171 text

No content

Slide 172

Slide 172 text

No content

Slide 173

Slide 173 text

No content

Slide 174

Slide 174 text

Search / buy music Upload songs Billing Profile

Slide 175

Slide 175 text

Search / buy music Upload songs Billing Profile

Slide 176

Slide 176 text

Search / buy music Upload songs Billing Profile

Slide 177

Slide 177 text

Search / buy music Upload songs Billing Profile

Slide 178

Slide 178 text

Layer Role Has domain knowledge? Services Dependencies Testing level Package Business logic Yes Provides services to bridge None / Language level Unit Bridge Wiring & Concretions Minimal Provides / forwards services to application layer Package / Symfony DI Integration Application / FW Talks to the outside world No Uses services provided by bridge layer Bridge End-to-end

Slide 179

Slide 179 text

Pros Cons Less boilerplate for creating separate services More boilerplate for integrating domain code Layers kept isolated & easily testable Scaling not 100% microservice-esque Clear separation of concerns Requires effort in understanding Easily port domain code into applications Not 100% separately deployable Easily switch between monolith or microservice Not truly asynchronous Communication via JSON between services Breaking one thing breaks all things Full log trace from request to response Low latency (method calls vs network calls)

Slide 180

Slide 180 text

No content

Slide 181

Slide 181 text

No content

Slide 182

Slide 182 text

WE ARE HIRING!