TDC2016SP - Trilha Developing for Business

129 visualizações

Publicada em

Developing for Business

Publicada em: Educação
  • Seja o primeiro a comentar

TDC2016SP - Trilha Developing for Business

  1. 1. Globalcode – Open4education Trilha – PHP Architecture Developing for Business
  2. 2. Globalcode – Open4education apresentação Antonio Spinelli @tonicospinelli tonicospinelli85@gmail.com
  3. 3. Globalcode – Open4education o propósito sempre é o mesmo: resolver problema para o negócio!
  4. 4. Globalcode – Open4education comportamento problema simples vs soluções complexas
  5. 5. Globalcode – Open4education comportamento escopo abstrato = problema desconhecido
  6. 6. Globalcode – Open4education comportamento agregue valor para negócio entenda a demanda agilidade não é "sobrinhagem"
  7. 7. Globalcode – Open4education conhecimento leia código peça e faça code review automatize tarefas repetitivas
  8. 8. Globalcode – Open4education user story Lista de Desejos Eu como usuário convidado, quero adicionar um produto esgotado em minha lista de desejos para que eu receba uma notificação quando este estiver disponível. Objetivo reposição mais inteligente de produtos
  9. 9. Globalcode – Open4education php estruturado
  10. 10. Globalcode – Open4education php estruturado adicionando um item na lista de desejos
  11. 11. Globalcode – Open4education // public/wishlist.php // ... if (isset($_POST['submit']) && isValidWishList($_POST['wish_item'])) { $wishItem = getWishList($_POST['wish_item']); $db->beginTransaction(); try { $stm = $db->prepare( 'INSERT INTO wishlists (email, product_id) VALUES (?, ?)' ); $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
  12. 12. Globalcode – Open4education php estruturado // public/wishlist.php // ... <table> <?php foreach ($wishlist as $wish): ?> <tr> <td><?php echo $wish['id']; ?> </td> <td><?php echo $wish['product_name']; ?> </td> <?php if ($wish['product_stock'] == 0): ?> <td>Not Available</td> <?php else: ?> <td>Available</td> <?php endif; ?> <td> <?php echo removeUrl($wish['id'], ['email' => $email]); ?> </td> </tr> <?php endforeach; ?> </table> // ...
  13. 13. Globalcode – Open4education php estruturado notificar usuário que o item está disponível
  14. 14. Globalcode – Open4education php estruturado // 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 $wishlist) { mail( $wishlist['email'], "{$wishlist['product_name']} disponível", $mailBody ); $stm = $db->prepare("UPDATE wishlists SET status='S' WHERE id=?"); $stm->execute([$wishlist['id']]); }
  15. 15. Globalcode – Open4education php estruturado Pronto! funciona!
  16. 16. Globalcode – Open4education php estruturado quais problemas neste código?
  17. 17. Globalcode – Open4education php estruturado organização pobre sem verificação de erro dificuldade de reusar código
  18. 18. Globalcode – Open4education php estruturado isolando a apresentação
  19. 19. Globalcode – Open4education php estruturado // templates/wishlist/list.php <table> <?php foreach ($wishlist as $wish): ?> <tr> <td><?php echo $wish['id']; ?> </td> <td><?php echo $wish['product_name']; ?> </td> <?php if ($wish['product_stock'] == 0): ?> <td>Not Available</td> <?php else: ?> <td>Available</td> <?php endif; ?> <td> <?php echo removeUrl($wish['id'], ['email' => $email]); ?> </td> </tr> <?php endforeach; ?> </table>
  20. 20. Globalcode – Open4education php estruturado isolando regras de negócio
  21. 21. Globalcode – Open4education php estruturado function isValidWishList(array $data); function getWishList(array $data); function findAllWishProducts($email); function addWishItem(array $data); function removeWishItem($id); function findAllWishlistsToNotify(); function wishlistNotified($id);
  22. 22. Globalcode – Open4education php estruturado interagindo com regra de negócio e apresentação
  23. 23. Globalcode – Open4education php estruturado public/wishlist.php require_once __DIR__ . '/../lib/functions.php'; require_once __DIR__ . '/../lib/models/wishlist.php'; require_once __DIR__ . '/../lib/dbconn.php'; if (isset($_POST['submit']) && isValidWishList($_POST['wish_item'])) { $wishItem = getWishList($_POST['wish_item']); if (addWishItem($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';
  24. 24. Globalcode – Open4education php estruturado isolando layout
  25. 25. Globalcode – Open4education php estruturado // template/layout.php <!DOCTYPE html> <html> <head> <title><?php echo $title ?></title> </head> <body> <?php echo $content ?> </body> </html>
  26. 26. Globalcode – Open4education php estruturado // 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' ?>
  27. 27. Globalcode – Open4education php estruturado front controller
  28. 28. Globalcode – Open4education php estruturado Without a front controller GET /wishlist.php?email=email@test.com With index.php as the front controller GET /index.php/wishlist/email@test.com
  29. 29. Globalcode – Open4education php puro front controller // public/index.php // load function files // 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>'; }
  30. 30. Globalcode – Open4education php estruturado autoload
  31. 31. Globalcode – Open4education php estruturado autoload // public/index.php require_once __DIR__ . '/../config/app.php'; require_once LIBRARY_DIR . '/functions.php'; require_once LIBRARY_DIR . '/models/wishlist.php'; require_once LIBRARY_DIR . '/controllers/wishlist.php'; // include_path is other alternative ini_set('include_path', __DIR__ . '/../lib');
  32. 32. Globalcode – Open4education php estruturado composer { "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" ] } }
  33. 33. Globalcode – Open4education php estruturado projeto 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
  34. 34. Globalcode – Open4education php business
  35. 35. Globalcode – Open4education php business clareza no código facilidade de crescimento testes automatizados
  36. 36. Globalcode – Open4education php business testes automatizados
  37. 37. Globalcode – Open4education php business testes automatizados garantem regras conhecidas auxiliam refatoração não evitam bugs
  38. 38. Globalcode – Open4education php business phpunit PHPUnit 5.4.6 by Sebastian Bergmann and contributors. ................................................... 59 / 59 (100%) Time: 349 ms, Memory: 6.00MB OK (59 tests, 126 assertions)
  39. 39. Globalcode – Open4education 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. php business phpunit
  40. 40. Globalcode – Open4education php business não confie em arrays evite abreviações
  41. 41. Globalcode – Open4education /** * 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 business array, não confie!
  42. 42. Globalcode – Open4education php business objetos de valor
  43. 43. Globalcode – Open4education php business objetos de valor são objetos simples encapsulam tipos primitivos representam o valor
  44. 44. Globalcode – Open4education class Status { const PENDING = 'P'; const SENT = 'S'; public function __construct($status) { $this->validate($status); $this->status = $status; } // … other methods public function equalsTo(Status $status) { return $status === $this; } } php business objetos de valor
  45. 45. Globalcode – Open4education php business entidades
  46. 46. Globalcode – Open4education php business entidades são mutáveis possuem identificador
  47. 47. Globalcode – Open4education 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; } } php business entidades
  48. 48. Globalcode – Open4education class WishlistItem { public function __construct( Id $id, $name, Available $isAvailable ) { $this->id = $id; $this->name = $name; $this->available = $isAvailable; } } php business entidades
  49. 49. Globalcode – Open4education php business repositórios
  50. 50. Globalcode – Open4education php business repositórios camada de persistência estratégia de armazenamento
  51. 51. Globalcode – Open4education interface WishlistRepository { public function find($id); public function findAllByEmail($email); public function add(Wishlist $wishlist); public function delete(Wishlist $wishlist); public function findAllToNotify(); } php business repositórios
  52. 52. Globalcode – Open4education 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'] ); } } php business repositórios
  53. 53. Globalcode – Open4education 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); } } php business repositórios
  54. 54. Globalcode – Open4education 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()); } } php business repositórios
  55. 55. Globalcode – Open4education 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}" ); } } php business repositórios
  56. 56. Globalcode – Open4education function wishlistListAction($email) { $db = dbConnect(); $factory = new WishlistFactory(); $repository = new WishlistPdoRepository($db, $factory); $wishlist = $repository->findAllByEmail($email); include TEMPLATE_DIR . '/wishlists/list.php'; } php business repositórios
  57. 57. Globalcode – Open4education php business serviços
  58. 58. Globalcode – Open4education php business serviços camada de operações orquestram os objetos definem o que fazer
  59. 59. Globalcode – Open4education $db = dbConnect(); $factory = new WishlistFactory(); $repository = new WishlistRepository($db, $factory); $resolver = new ItemResolver(new ProductRepository($db)); try { $intention = getIntention($request['wish_item']); $useCase = new AddItemWishlistUseCase( $repository, $factory, $resolver ); $wishlist = $useCase->execute($intention); $successmsg = "{$wishlist->getItemName()} added!"; } catch (Exception $e) { $errormsg = $e->getMessage(); } php business serviços
  60. 60. Globalcode – Open4education class AddItemWishlistUseCase { public function execute(AddItemIntention $intention) { $item = $this->resolver->resolve($intention->itemId); try { $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 business serviços
  61. 61. Globalcode – Open4education // 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(); $intention = new NotifyProductsAvailableIntention($pending); $useCase = new NotifyProductsAvailableUseCase($repository, $notifier); $useCase->execute($intention); php business serviços
  62. 62. Globalcode – Open4education class NotifyProductsAvailableUseCase { public function __construct($repository, $notifier) public function execute(NotifyProductsIntention $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); } } } php business serviços
  63. 63. Globalcode – Open4education php business injeção de dependências
  64. 64. Globalcode – Open4education php business injeção de dependência princípio da inversão de dependência dependências configuráveis
  65. 65. Globalcode – Open4education php business injeção de dependência Respect/Config
  66. 66. Globalcode – Open4education // 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] php business injeção de dependência
  67. 67. Globalcode – Open4education // 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 validation */) { wishlistAddAction($container, $_GET['email'], $_POST); } php business injeção de dependência
  68. 68. Globalcode – Open4education function wishlistAddAction(Container $container, $email, $request) { try { $intention = getIntention($request['wish_item']); $useCase = $container->wishlistAddItemWishlistUseCase; $wishlist = $useCase->execute($intention); $successmsg = "{$wishlist->getItemName()} added!"; } catch (Exception $e) { $errormsg = $e->getMessage(); } } php business injeção de dependência
  69. 69. Globalcode – Open4education php business eventos
  70. 70. Globalcode – Open4education php business eventos mecanismo de inversão de controle comunicação assíncrona baixo acoplamento
  71. 71. Globalcode – Open4education php business eventos symfony/event-dispatcher
  72. 72. Globalcode – Open4education class UpdateProductUseCase { public function __construct($repository, $factory, $eventDispatcher); public function execute(Intention $intention) { // do something $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; } } php business eventos
  73. 73. Globalcode – Open4education class StockListener { public function __construct(NotifyProductAvailable $useCase); public function __invoke(ProductStockIncreasedEvent $event) { $productId = $event->getProduct()->getId(); $intention = new NotifyProductIntention($productId); $this->useCase->execute($intention); } } php business eventos
  74. 74. Globalcode – Open4education config/app.ini [wishlistStockListener StockHasIncreasedListener] useCase = [notifyProductAvailableUseCase] [eventDispatcher EventDispatcher] addListener[] = ["product.stock.increased", [wishlistStockListener]] [productUpdateUseCase UpdateProductUseCase] __construct = [[repository], [factory], [eventDispatcher]] php business eventos
  75. 75. Globalcode – Open4education php business estrutura
  76. 76. Globalcode – Open4education camadas business use cases application web devices useinterface database ExternalInterfaces
  77. 77. Globalcode – Open4education // public/wishlist.php // ... if (isset($_POST['submit']) && isValidWishList($_POST['wish_item'])) { $wishItem = getWishList($_POST['wish_item']); $db->beginTransaction(); try { $stm = $db->prepare( 'INSERT INTO wishlists (email, product_id) VALUES (?, ?)' ); $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
  78. 78. Globalcode – Open4education function wishlistAddAction(Container $container, $email, $request) { try { $intention = getIntention($request['wish_item']); $useCase = $container->wishlistAddItemWishlistUseCase; $wishlist = $useCase->execute($intention); $successmsg = "{$wishlist->getItemName()} added!"; } catch (Exception $e) { $errormsg = $e->getMessage(); } } php business
  79. 79. Globalcode – Open4education estrutura inicial developing-for-business ├── cli │ ├── create_tables.php │ └── wishlist_notification.php ├── data │ └── business.db ├── lib │ ├── dbconn.php │ └── functions.php └── public ├── product.php └── wishlist.phpw
  80. 80. Globalcode – Open4education estrutura de negócio developing-for-business └── src └── Application ├── Product │ ├── Controllers │ └── Repositories └── ProductWishlist ├── Controllers ├── Listeners └── Repositories developing-for-business └── src ├── Product │ ├── Events │ ├── Exceptions │ ├── Intentions │ ├── Repositories │ └── UseCases └── Wishlist ├── Exceptions ├── Intentions ├── Repositories └── UseCases
  81. 81. Globalcode – Open4education conclusão saia da zona de conforto testes automatizados domain driven design domain specific language princípio solid
  82. 82. Globalcode – Open4education Life's too short for bad software Lew Cirne, New Relic
  83. 83. Globalcode – Open4education Implementing Domain-Driven Design by Vaughn Vernon Patterns of Enterprise Application Architecture by Martin Fowler Domain-Driven Design by Eric Evans DDD in PHP by Carlos Buenosvinos, Christian Soronellas and Keyvan Akbary referências
  84. 84. Globalcode – Open4education Obrigado tonicospinelli/developing-for-business https://joind.in/talk/ad6a7

×