modernizando a arquitertura de sua aplicação

446 views

Published on

Partindo de um código legado com uma organização frágil e pouco reutilizável iremos aprimorá-lo de forma incremental e com foco nas regras de negócio. Utilizaremos princípios de projeto orientado a objetos para torná-lo mais fácil de testar e reutilizar deixando o seu código mais robusto e escalável.

Published in: Technology
  • Be the first to comment

modernizando a arquitertura de sua aplicação

  1. 1. modernizando a arquitertura de sua aplicação Antonio Spinelli @tonicospinelli tornando o seu código mais robusto e escalável
  2. 2. problema simples vs soluções complexas
  3. 3. soluções simples
  4. 4. o objetivo não muda: resolver problemas para o negócio!
  5. 5. entenda o problema agregue valor ao negócio agilidade não é "sobrinhagem" desenvolvedor
  6. 6. desenvolvedor automatize tarefas repetidas peça e faça code review leia código
  7. 7. Lista de Desejos para Produtos Eu como um usuário convidado, quero adicionar um produto indisponível dentro da minha lista de desejos, de modo que eu receba uma notificação quando este estiver disponível. Objetivo reposição de estoque inteligente e estreitar relacionamento com cliente user story
  8. 8. php puro
  9. 9. adicionando um item na lista de desejos php puro
  10. 10. // public/wishlist.php // ... if (isset($_POST['submit']) && isValid($_POST['wish_item'])) { } // ... php puro
  11. 11. // public/wishlist.php // ... if (isset($_POST['submit']) && isValid($_POST['wish_item'])) { $wishItem = createWishListItem($_POST['wish_item']); } // ... php puro
  12. 12. // public/wishlist.php // ... if (isset($_POST['submit']) && isValid($_POST['wish_item'])) { $wishItem = createWishListItem($_POST['wish_item']); $stm = $db->prepare('insert new entry (email, product_id)'); $stm->execute([$wishItem['email'], $wishItem['product_id']]); $successmsg = 'Product was added at wish list successfully!'; } // ... php puro
  13. 13. // public/wishlist.php // ... if (isset($_POST['submit']) && isValid($_POST['wish_item'])) { $wishItem = createWishListItem($_POST['wish_item']); $db->beginTransaction(); try { $stm = $db->prepare('insert new entry (email, product_id)'); $stm->execute([$wishItem['email'], $wishItem['product_id']]); $successmsg = 'Product was added at wish list successfully!'; $db->commit(); } catch (Exception $e) { $db->rollBack(); $errormsg = 'Product could not be added at wishlist! :('; } } // .. php puro
  14. 14. // public/wishlist.php // ... <table> <?php foreach ($wishlist as $item): ?> <tr> <td><?php echo $item['id']; ?> </td> <td><?php echo $item['product_name']; ?> </td> <?php if ($item['product_stock'] == 0): ?> <td>Not Available</td> <?php else: ?> <td>Available</td> <?php endif; ?> <td> <?php echo removeUrl($item['id'], ['email' => $email]); ?> </td> </tr> <?php endforeach; ?> </table> // ... php puro
  15. 15. notificar usuário quando o item estiver disponível php puro
  16. 16. // cli/wishlist_notify.php // ... $query = "find all available products from wishlist"; $stm = $db->prepare($query); $stm->execute(); $wishlists = $stm->fetchAll(PDO::FETCH_ASSOC); php puro
  17. 17. // cli/wishlist_notify.php // ... $query = "find all available products from wishlist"; $stm = $db->prepare($query); $stm->execute(); $wishlists = $stm->fetchAll(PDO::FETCH_ASSOC); foreach ($wishlists as $item) { mail( $item['email'], "{$item['product_name']} available", $mailBody ); $stm = $db->prepare("define new status for id = ?"); $stm->execute([$item['id']]); } php puro
  18. 18. pronto! funciona! php puro
  19. 19. quais problemas temos com este código? atenção
  20. 20. organização pobre sem verificação de erros dificuldade para reutilizar o código php puro
  21. 21. php estruturado
  22. 22. isolando a apresentação php estruturado
  23. 23. // templates/wishlist/list.php <table> <?php foreach ($wishlist as $item): ?> <tr> <td><?php echo $item['id']; ?> </td> <td><?php echo $item['product_name']; ?> </td> <?php if ($item['product_stock'] == 0): ?> <td>Not Available</td> <?php else: ?> <td>Available</td> <?php endif; ?> <td> <?php echo removeUrl($item['id'], ['email' => $email]); ?> </td> </tr> <?php endforeach; ?> </table> php estruturado
  24. 24. isolando regra de negócio php estruturado
  25. 25. // lib/models/wishlist.php function addItemIntoWishlist(array $data); function createWishListItem(array $data); function findAllWishlistsToNotify(); function findAllWishProducts($email); function isValidWishList(array $data); function removeWishItem($id); function wishlistNotified($id); php estruturado
  26. 26. interagindo regras de negócio com a apresentação php estruturado
  27. 27. // public/wishlist.php require_once __DIR__ . '/../lib/dbconn.php'; require_once __DIR__ . '/../lib/functions.php'; require_once __DIR__ . '/../lib/wishlist.php'; if (isset($_POST['submit']) && isValidWishList($_POST['wish_item'])) { $wishItem = createWishListItem($_POST['wish_item']); $db->beginTransaction(); try { $stm = $db->prepare('insert new entry (email, product_id)'); $stm->execute([$wishItem['email'], $wishItem['product_id']]); $db->commit(); $successmsg = 'Product was added at wish list successfully!'; } catch (Exception $e) { $db->rollBack(); $errormsg = 'Product could not be added at wishlist! :('; } } // ... php estruturado
  28. 28. // public/wishlist.php require_once __DIR__ . '/../lib/dbconn.php'; require_once __DIR__ . '/../lib/functions.php'; require_once __DIR__ . '/../lib/wishlist.php'; if (isset($_POST['submit']) && isValidWishList($_POST['wish_item'])) { $wishItem = createWishListItem($_POST['wish_item']); $db->beginTransaction(); try { $stm = $db->prepare('insert new entry (email, product_id)'); $stm->execute([$wishItem['email'], $wishItem['product_id']]); $db->commit(); $successmsg = 'Product was added at wish list successfully!'; } catch (Exception $e) { $db->rollBack(); $errormsg = 'Product could not be added at wishlist! :('; } } // ... structured php
  29. 29. // public/wishlist.php require_once __DIR__ . '/../lib/dbconn.php'; require_once __DIR__ . '/../lib/functions.php'; require_once __DIR__ . '/../lib/wishlist.php'; if (isset($_POST['submit']) && isValidWishList($_POST['wish_item'])) { $wishItem = createWishListItem($_POST['wish_item']); if (addItemIntoWishlist($wishItem)) { $successmsg = 'Product was added at wish list successfully!'; } else { $errormsg = 'Product could not be added at wishlist! :('; } } // ... php estruturado
  30. 30. // public/wishlist.php require_once __DIR__ . '/../lib/dbconn.php'; require_once __DIR__ . '/../lib/functions.php'; require_once __DIR__ . '/../lib/wishlist.php'; if (isset($_POST['submit']) && isValidWishList($_POST['wish_item'])) { $wishItem = createWishListItem($_POST['wish_item']); if (addItemIntoWishlist($wishItem)) { $successmsg = 'Product was added at wish list successfully!'; } else { $errormsg = 'Product could not be added at wishlist! :('; } } $wishlist = findAllWishProducts($_GET['email']); include __DIR__ . '/../templates/wishlists/list.php'; php estruturado
  31. 31. isolando layout php estruturado
  32. 32. // template/layout.php <!DOCTYPE html> <html> <head> <title><?php echo $title ?></title> </head> <body> <?php echo $content ?> </body> </html> layout padrão php estruturado
  33. 33. // template/wishlist/list.php <?php $title = 'My Wish List' ?> define o título da página php estruturado
  34. 34. // template/wishlist/list.php <?php $title = 'My Wish List' ?> <?php ob_start() ?> <table> <tbody> <?php foreach ($wishlist as $wish): ?> <tr><!-- print all columns --></tr> <?php endforeach; ?> </tbody> </table> <?php $content = ob_get_clean() ?> define o conteúdo da página php estruturado
  35. 35. // template/wishlist/list.php <?php $title = 'My Wish List' ?> <?php ob_start() ?> <table> <tbody> <?php foreach ($wishlist as $wish): ?> <tr><!-- print all columns --></tr> <?php endforeach; ?> </tbody> </table> <?php $content = ob_get_clean() ?> <?php include __DIR__ . '/../layout.php' ?> extendendo layout padrão php estruturado
  36. 36. front controller php estruturado
  37. 37. sem um front controller GET /wishlist.php?email=email@test.com com index.php como um front controller GET /index.php/wishlist/email@test.com com regras de sobrescrita no servidor web GET /wishlist/email@test.com php estruturado
  38. 38. // public/index.php // route the request internally $uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH); $method = $_SERVER['REQUEST_METHOD']; if (preg_match('/wishlist/(.*)$', $uri, $matches) && $method == 'GET') { wishlistListAction($matches[1]); } elseif ('/index.php/wishlist/add' === $uri && $method == 'POST') { wishlistAddAction($_GET['email'], $_POST); } else { header('HTTP/1.1 404 Not Found'); echo '<html><body><h1>Page Not Found</h1></body></html>'; } php estruturado
  39. 39. // public/index.php // route the request internally $uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH); $method = $_SERVER['REQUEST_METHOD']; if (preg_match('/wishlist/(.*)$', $uri, $matches) && $method == 'GET') { wishlistListAction($matches[1]); } elseif ('/index.php/wishlist/add' === $uri && $method == 'POST') { wishlistAddAction($_GET['email'], $_POST); } else { header('HTTP/1.1 404 Not Found'); echo '<html><body><h1>Page Not Found</h1></body></html>'; } php estruturado
  40. 40. // public/index.php // route the request internally $uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH); $method = $_SERVER['REQUEST_METHOD']; if (preg_match('/wishlist/(.*)$', $uri, $matches) && $method == 'GET') { wishlistListAction($matches[1]); } elseif ('/index.php/wishlist/add' === $uri && $method == 'POST') { wishlistAddAction($_GET['email'], $_POST); } else { header('HTTP/1.1 404 Not Found'); echo '<html><body><h1>Page Not Found</h1></body></html>'; } php estruturado
  41. 41. // public/index.php // route the request internally $uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH); $method = $_SERVER['REQUEST_METHOD']; if (preg_match('/wishlist/(.*)$', $uri, $matches) && $method == 'GET') { wishlistListAction($matches[1]); } elseif ('/index.php/wishlist/add' === $uri && $method == 'POST') { wishlistAddAction($_GET['email'], $_POST); } else { header('HTTP/1.1 404 Not Found'); echo '<html><body><h1>Page Not Found</h1></body></html>'; } php estruturado
  42. 42. autoload php estruturado
  43. 43. // public/index.php require_once __DIR__ . '/../config/app.php'; require_once LIBRARY_DIR . '/functions.php'; require_once LIBRARY_DIR . '/wishlist.php'; // include_path is other alternative ini_set('include_path', __DIR__ . '/../lib'); php estruturado autoload
  44. 44. php estruturado
  45. 45. { "name": "tonicospinelli/developing-for-business", "description": "A Quick Project for Talk", "license": "MIT", "autoload": { "files": [ "./lib/dbconn.php", "./lib/functions.php", "./lib/controllers/wishlist.php", "./lib/models/wishlist.php" ] } } composer php estruturado
  46. 46. $ composer dump-autoload // public/index.php require_once __DIR__ . '/../vendor/autoload.php'; php estruturado autoload
  47. 47. developing-for-business ├── cli │ └── wishlist_notification.php ├── composer.json ├── config │ └── app.php ├── lib │ ├── controllers │ │ └── wishlist.php │ ├── functions.php │ └── models │ └── wishlist.php ├── public │ └── index.php ├── templates │ └── wishlists └── vendor estrutura do projeto php estruturado
  48. 48. php orientado a objetos
  49. 49. código auto explicativo facilidade no crescimento testes automatizados php orientado a objetos
  50. 50. testes automatizados php orientado a objetos
  51. 51. garantem regras conhecidas auxiliam na refatoração não evitam bugs testes automatizados php orientado a objetos
  52. 52. PHPUnit 5.4.6 by Sebastian Bergmann and contributors. ................................................... 59 / 59 (100%) Time: 349 ms, Memory: 6.00MB OK (59 tests, 126 assertions) testes automatizados php orientado a objetos
  53. 53. PHPUnit 5.4.6 by Sebastian Bergmann and contributors. ..................................F................ 59 / 59 (100%) Time: 374 ms, Memory: 6.00MB There was 1 failure: 1) ProductTest::testUpdateProductFailed Failed asserting that exception of type "ProductException" is thrown. FAILURES! Tests: 59, Assertions: 125, Failures: 1. testes automatizados php orientado a objetos
  54. 54. não confie em arrays evite abreviações php orientado a objetos
  55. 55. /** * Creates a new wish list data. * @param array $data * @return array */ function newWishList(array $data) { return array( 'email' => isset($data['email']) ? $data['email'] : null), 'product_id' => $data['product_id'], 'status' => 'P', ); } php orientado a objetos
  56. 56. objetos de valor php orientado a objetos
  57. 57. objetos simples encapsulam tipos primitivos representam o valor objetos de valor php orientado a objetos
  58. 58. class Status { const PENDING = 'P'; const SENT = 'S'; private $status; public function __construct($status) { $this->validate($status); $this->status = $status; } // … other methods public function equalsTo(Status $status) { return $status === $this; } } objetos de valor php orientado a objetos
  59. 59. entidades php orientado a objetos
  60. 60. são mutáveis tem identificador entidades php orientado a objetos
  61. 61. class Wishlist { public function __construct( Id $id, Email email, WishlistItem $item, Status $status ) { $this->id = $id; $this->email = $email; $this->item = $item; $this->status = $status; } } entidades php orientado a objetos
  62. 62. class Wishlist { public function __construct( Id $id, Email email, WishlistItem $item, Status $status ) { $this->id = $id; $this->email = $email; $this->item = $item; $this->status = $status; } } por que um objeto Item? entidades php orientado a objetos
  63. 63. class Wishlist { public function __construct( Id $id, Email email, WishlistItem $item, Status $status ) { $this->id = $id; $this->email = $email; $this->item = $item; $this->status = $status; } } por que um objeto Item? Produtos Presente entidades php orientado a objetos
  64. 64. interface WishlistItem { public function getId(); } class WishlistProduct implements WishlistItem { public function __construct( Id $id, $name, Available $availability ) { $this->id = $id; $this->name = $name; $this->available = $availability; } } entidades php orientado a objetos
  65. 65. repositórios php orientado a objetos
  66. 66. camada de persistência estratégia de armazenamento repositórios php orientado a objetos
  67. 67. interface WishlistRepository { public function add(Wishlist $wishlist); public function delete(Wishlist $wishlist); public function find($id); public function findAllByEmail($email); public function findAllToNotify(); } repositórios php orientado a objetos
  68. 68. namespace DevelopBusinessApplicationProductWishlistRepositories; class PdoRepository implements WishlistRepository { public function __construct(PDO $driver, Factory $factory); public function findAllByEmail($email) { $query = "find all items by email"; $stm = $this->driver->prepare($query); $stm->execute([$email]); return $stm->fetchAll( PDO::FETCH_FUNC, [$this->factory, 'create'] ); } } repositórios php orientado a objetos
  69. 69. namespace DevelopBusinessApplicationProductWishlistRepositories; class RedisRepository implements WishlistRepository { public function __construct(Predis $driver, Factory $factory); public function find($id) { $wishlist = $this->driver->get($this->getKey($id)); if (!$wishlist) { throw WishlistNotFoundException::byIdentifier($id); } return $this->factory->fromJson($wishlist); } } repositórios php orientado a objetos
  70. 70. class PdoRepositoryTest extends PHPUnit_Framework_TestCase { public function testAddNewRowSuccessful() { $wishlist = $this->factory->fromQueryResult(/* args */); $pdoSpy = new PDOSpy(); (new Repository($pdoSpy))->add($wishlist); $this->assertTrue($pdoSpy->beginTransactionCalled); $this->assertTrue($pdoSpy->commitCalled); $this->assertEquals(2, $wishlist->getId()); } } como testar repositórios? php orientado a objetos
  71. 71. class PDOSpy extends PDO { public function beginTransaction() { $this->beginTransactionCalled = true; } public function prepare($statement, $options = null) { if ($statement == INSERT INTO wishlists VALUES (?, ?, ?)') { return new WriteStatementStub($this->failureOnWrite); } throw new InvalidArgumentException( "None Stub Statement was found for query: {$statement}" ); } } como testar repositórios? php orientado a objetos
  72. 72. function wishlistListAction($email) { $db = dbConnect(); $factory = new WishlistFactory(); $repository = new WishlistPdoRepository($db, $factory); $wishlist = $repository->findAllByEmail($email); include TEMPLATE_DIR . '/wishlists/list.php'; } repositórios php orientado a objetos
  73. 73. serviços php orientado a objetos
  74. 74. camada de operação orquestra os objetos define o que fazer serviços php orientado a objetos
  75. 75. adicionando um item na lista de desejos serviços php orientado a objetos
  76. 76. $db = dbConnect(); $factory = new WishlistFactory(); $repository = new WishlistRepository($db, $factory); $resolver = new ItemResolver(new ProductRepository($db)); try { $intention = createIntention($request['wish_item']); $useCase = new AddItemWishlistUseCase( $repository, $factory, $resolver ); $wishlist = $useCase->execute($intention); $successmsg = "{$wishlist->getItemName()} added!"; } catch (DomainException $e) { $errormsg = $e->getMessage(); } resolvendo dependências adicionando um item na lista de desejos php orientado a objetos
  77. 77. $db = dbConnect(); $factory = new WishlistFactory(); $repository = new WishlistRepository($db, $factory); $resolver = new ItemResolver(new ProductRepository($db)); try { $intention = createIntention($request['wish_item']); $useCase = new AddItemWishlistUseCase( $repository, $factory, $resolver ); $wishlist = $useCase->execute($intention); $successmsg = "{$wishlist->getItemName()} added!"; } catch (DomainException $e) { $errormsg = $e->getMessage(); } parsing da requisição adicionando um item na lista de desejos php orientado a objetos
  78. 78. $db = dbConnect(); $factory = new WishlistFactory(); $repository = new WishlistRepository($db, $factory); $resolver = new ItemResolver(new ProductRepository($db)); try { $intention = createIntention($request['wish_item']); $useCase = new AddItemWishlistUseCase( $repository, $factory, $resolver ); $wishlist = $useCase->execute($intention); $successmsg = "{$wishlist->getItemName()} added!"; } catch (DomainException $e) { $errormsg = $e->getMessage(); } criando objeto de serviço adicionando um item na lista de desejos php orientado a objetos
  79. 79. $db = dbConnect(); $factory = new WishlistFactory(); $repository = new WishlistRepository($db, $factory); $resolver = new ItemResolver(new ProductRepository($db)); try { $intention = createIntention($request['wish_item']); $useCase = new AddItemWishlistUseCase( $repository, $factory, $resolver ); $wishlist = $useCase->execute($intention); $successmsg = "{$wishlist->getItemName()} added!"; } catch (DomainException $e) { $errormsg = $e->getMessage(); } executando o serviço adicionando um item na lista de desejos php orientado a objetos
  80. 80. $db = dbConnect(); $factory = new WishlistFactory(); $repository = new WishlistRepository($db, $factory); $resolver = new ItemResolver(new ProductRepository($db)); try { $intention = createIntention($request['wish_item']); $useCase = new AddItemWishlistUseCase( $repository, $factory, $resolver ); $wishlist = $useCase->execute($intention); $successmsg = "{$wishlist->getItemName()} added!"; } catch (DomainException $e) { $errormsg = $e->getMessage(); } mensagem de negócio adicionando um item na lista de desejos php orientado a objetos
  81. 81. class AddItemWishlistUseCase { public function __construct( WishlistRepository $repository, WishlistFactory $factory, ItemResolver $resolver ) { // do something } } como adicionar um item na lista de desejos php orientado a objetos
  82. 82. class AddItemWishlistUseCase { public function execute(AddItemIntention $intention) { $item = $this->resolver->resolve($intention->itemId); try { $wishlist = $this->repository->findOneByEmailAndItem( $email, $item ); throw WishlistException::itemAlreadyExists($wishlist); } catch (WishlistNotFoundException $e) { // do nothing } $wishlist = $this->factory->new($email, $item); return $this->repository->add($wishlist); } } php orientado a objetos como adicionar um item na lista de desejos
  83. 83. class AddItemWishlistUseCase { public function execute(AddItemIntention $intention) { $item = $this->resolver->resolve($intention->itemId); try { $wishlist = $this->repository->findOneByEmailAndItem( $email, $item ); throw WishlistException::itemAlreadyExists($wishlist); } catch (WishlistNotFoundException $e) { // do nothing } $wishlist = $this->factory->new($email, $item); return $this->repository->add($wishlist); } } php orientado a objetos como adicionar um item na lista de desejos
  84. 84. class AddItemWishlistUseCase { public function execute(AddItemIntention $intention) { $item = $this->resolver->resolve($intention->itemId); try { $wishlist = $this->repository->findOneByEmailAndItem( $email, $item ); throw WishlistException::itemAlreadyExists($wishlist); } catch (WishlistNotFoundException $e) { // do nothing } $wishlist = $this->factory->new($email, $item); return $this->repository->add($wishlist); } } php orientado a objetos como adicionar um item na lista de desejos
  85. 85. serviços notificar usuário quando um item estiver disponível php orientado a objetos
  86. 86. // cli/wishlist_notify.php require_once __DIR__ . '/../config/app.php'; require_once __DIR__ . '/../vendor/autoload.php'; $factory = new WishlistFactory(); $repository = new WishlistRepository(dbConnect(), $factory); $notifier = new MailNotifier(); $useCase = (new NotifyItemsUseCase($repository, $notifier); $useCase->execute(new NotifyItemsIntention(Status::PENDING)); notificar quando um item disponível resolving dependencies php orientado a objetos
  87. 87. // cli/wishlist_notify.php require_once __DIR__ . '/../config/app.php'; require_once __DIR__ . '/../vendor/autoload.php'; $factory = new WishlistFactory(); $repository = new WishlistRepository(dbConnect(), $factory); $notifier = new MailNotifier(); $useCase = (new NotifyItemsUseCase($repository, $notifier); $useCase->execute(new NotifyItemsIntention(Status::PENDING)); call service notificar quando um item disponível php orientado a objetos
  88. 88. class NotifyItemsUseCase { public function execute(NotifyItemsIntention $intention) { $status = $intention->getStatus(); $wishlists = $this->repository->findAllByStatus($status); foreach ($wishlists as $wishlist) { $this->notifier()->send($wishlist); $wishlist->changeStatusTo(Status::sent()); $this->repository->update($wishlist); } } } como notificar quando um item disponível? php orientado a objetos
  89. 89. class NotifyItemsUseCase { public function execute(NotifyItemsIntention $intention) { $status = $intention->getStatus(); $wishlists = $this->repository->findAllByStatus($status); foreach ($wishlists as $wishlist) { $this->notifier()->send($wishlist); $wishlist->changeStatusTo(Status::sent()); $this->repository->update($wishlist); } } } como notificar quando um item disponível? php orientado a objetos
  90. 90. class NotifyItemsUseCase { public function execute(NotifyItemsIntention $intention) { $status = $intention->getStatus(); $wishlists = $this->repository->findAllByStatus($status); foreach ($wishlists as $wishlist) { $this->notifier()->send($wishlist); $wishlist->changeStatusTo(Status::sent()); $this->repository->update($wishlist); } } } como notificar quando um item disponível? php orientado a objetos
  91. 91. injeção de dependência php orientado a objetos
  92. 92. princípio da inversão de dependência dependências configuráveis injeção de dependência php orientado a objetos
  93. 93. Respect/Config injeção de dependência php orientado a objetos
  94. 94. // config/app.ini [databaseConnection PDO] __construct = ["sqlite:../data/business.db", null, null] [factory WishlistFactory] [repository WishlistRepository] __construct = [[databaseConnection], [factory]] [productRepository ProductRepository] driver = [databaseConnection] [itemResolver WishlistItemResolver] product = [productRepository] injeção de dependência php orientado a objetos
  95. 95. // public/index.php require_once __DIR__ . '/../config/app.php'; require_once __DIR__ . '/../vendor/autoload.php'; $configFile = __DIR__ . '/../config/app.ini'; $container = new RespectConfigContainer($configFile); if ('/index.php/wishlist/add' === $uri /* other validations */) { wishlistAddAction($container, $_GET['email'], $_POST); } injeção de dependência php orientado a objetos
  96. 96. // public/index.php require_once __DIR__ . '/../config/app.php'; require_once __DIR__ . '/../vendor/autoload.php'; $configFile = __DIR__ . '/../config/app.ini'; $container = new RespectConfigContainer($configFile); if ('/index.php/wishlist/add' === $uri /* other validations */) { wishlistAddAction($container, $_GET['email'], $_POST); } injeção de dependência php orientado a objetos
  97. 97. function wishlistAddAction(Container $container, $email, $request) { try { $intention = createIntention($request['wish_item']); $useCase = $container->wishlistAddItemWishlistUseCase; $wishlist = $useCase->execute($intention); $successmsg = "{$wishlist->getItemName()} added!"; } catch (Exception $e) { $errormsg = $e->getMessage(); } } injeção de dependência php orientado a objetos
  98. 98. eventos php orientado a objetos
  99. 99. mecanismo de inversão de controle comunicação assíncrona baixo acoplamento eventos php orientado a objetos
  100. 100. symfony/event-dispatcher eventos php orientado a objetos
  101. 101. class UpdateProductUseCase { public function __construct(/* args */, $eventDispatcher); public function execute(Intention $intention) { $this->repository->update($updatedProduct); $event = new ProductWasUpdated($updatedProduct); $this->dispatch('product.updated', $event); return $updatedProduct; } } eventos php orientado a objetos
  102. 102. class UpdateProductUseCase { public function __construct(/* args */, $eventDispatcher); public function execute(Intention $intention) { $this->repository->update($updatedProduct); $event = new ProductWasUpdated($updatedProduct); $this->dispatch('product.updated', $event); if ($this->isStockIncreased($product, $updatedProduct)) { $this->dispatch('product.stock.increased', $event); } return $updatedProduct; } } eventos php orientado a objetos
  103. 103. class StockHasIncreasedListener { public function __construct(NotifyProductAvailable $useCase); public function __invoke(ProductStockIncreasedEvent $event) { $productId = $event->getProduct()->getId(); $intention = new NotifyProductIntention($productId); $this->useCase->execute($intention); } } events object oriented php
  104. 104. config/app.ini [wishlistStockListener StockHasIncreasedListener] useCase = [notifyProductAvailableUseCase] [eventDispatcher EventDispatcher] addListener[] = ["product.stock.increased",[wishlistStockListener]] [productUpdateUseCase UpdateProductUseCase] __construct = [[repository], [factory], [eventDispatcher]] eventos php orientado a objetos
  105. 105. estrutura php orientado a objetos
  106. 106. business services application web devices useinterface database ExternalInterfaces camadas php orientado a objetos
  107. 107. // public/wishlist.php // ... if (isset($_POST['submit']) && isValid($_POST['wish_item'])) { $wishItem = createWishListItem($_POST['wish_item']); $db->beginTransaction(); try { $stm = $db->prepare('insert new entry (email, product_id)'); $stm->execute([$wishItem['email'], $wishItem['product_id']]); $db->commit(); $successmsg = 'Product was added at wish list successfully!'; } catch (Exception $e) { $db->rollBack(); $errormsg = 'Product could not be added at wishlist! :('; } } // .. php puro
  108. 108. // lib/controllers/wishList.php function wishlistAddAction(Container $container, $email, $request) { try { $intention = createIntention($request['wish_item']); $useCase = $container->wishlistAddItemWishlistUseCase; $wishlist = $useCase->execute($intention); $successmsg = "{$wishlist->getItemName()} added!"; } catch (Exception $e) { $errormsg = $e->getMessage(); } } php orientado a objetos
  109. 109. developing-for-business ├── cli │ └── wishlist_notification.php ├── data │ └── business.db ├── lib │ ├── dbconn.php │ └── functions.php └── public └── wishlist.php estrutura php puro
  110. 110. DevelopBusiness └── Application ├── Product │ ├── Controllers │ └── Repositories └── ProductWishlist ├── Controllers ├── Resolver ├── Listeners └── Repositories DevelopBusiness ├── Product │ ├── Events │ ├── Exceptions │ ├── Intentions │ ├── Repositories │ └── UseCases └── Wishlist ├── Exceptions ├── Intentions ├── ItemResolver.php ├── Repositories └── UseCases estrutura php orientado a objetos
  111. 111. conclusão saia da zona de conforto
  112. 112. interaja com a comunidade conclusão
  113. 113. automatize tarefas repetitivas conclusão
  114. 114. domain driven design conclusão
  115. 115. domain specific language conclusão
  116. 116. princípio S.O.L.I.D. conclusão
  117. 117. Implementing Domain-Driven Design por Vaughn Vernon Patterns of Enterprise Application Architecture por Martin Fowler Domain-Driven Design por Eric Evans DDD in PHP por Carlos Buenosvinos, Christian Soronellas e Keyvan Akbary referências
  118. 118. Life's too short for bad software Lew Cirne, New Relic

×