modernizando a arquitertura de sua aplicação

118
modernizando a arquitertura de sua aplicação Antonio Spinelli @tonicospinelli tornando o seu código mais robusto e escalável

Upload: antonio-oertel-spinelli

Post on 09-Jan-2017

245 views

Category:

Technology


2 download

TRANSCRIPT

Page 1: modernizando a arquitertura  de sua aplicação

modernizando a arquitertura de sua aplicação

Antonio Spinelli @tonicospinelli

tornando o seu código mais robusto e escalável

Page 2: modernizando a arquitertura  de sua aplicação

problema simplesvs

soluções complexas

Page 3: modernizando a arquitertura  de sua aplicação

soluções simples

Page 4: modernizando a arquitertura  de sua aplicação

o objetivo não muda:

resolver problemas para o negócio!

Page 5: modernizando a arquitertura  de sua aplicação

entenda o problema

agregue valor ao negócio

agilidade não é "sobrinhagem"

desenvolvedor

Page 6: modernizando a arquitertura  de sua aplicação

desenvolvedor

automatize tarefas repetidas

peça e faça code review

leia código

Page 7: modernizando a arquitertura  de sua aplicação

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

Page 8: modernizando a arquitertura  de sua aplicação

php puro

Page 9: modernizando a arquitertura  de sua aplicação

adicionando um item na lista de desejos

php puro

Page 10: modernizando a arquitertura  de sua aplicação

// public/wishlist.php// ...if (isset($_POST['submit']) && isValid($_POST['wish_item'])) {

}// ...

php puro

Page 11: modernizando a arquitertura  de sua aplicação

// public/wishlist.php// ...if (isset($_POST['submit']) && isValid($_POST['wish_item'])) {

$wishItem = createWishListItem($_POST['wish_item']); }// ...

php puro

Page 12: modernizando a arquitertura  de sua aplicação

// 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

Page 13: modernizando a arquitertura  de sua aplicação

// 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

Page 14: modernizando a arquitertura  de sua aplicação

// 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

Page 15: modernizando a arquitertura  de sua aplicação

notificar usuário quando o item estiver disponível

php puro

Page 16: modernizando a arquitertura  de sua aplicação

// 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

Page 17: modernizando a arquitertura  de sua aplicação

// 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

Page 18: modernizando a arquitertura  de sua aplicação

pronto!

funciona!

php puro

Page 19: modernizando a arquitertura  de sua aplicação

quais problemas temos com este código?

atenção

Page 20: modernizando a arquitertura  de sua aplicação

organização pobre

sem verificação de erros

dificuldade para reutilizar o código

php puro

Page 21: modernizando a arquitertura  de sua aplicação

php estruturado

Page 22: modernizando a arquitertura  de sua aplicação

isolando a apresentação

php estruturado

Page 23: modernizando a arquitertura  de sua aplicação

// 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

Page 24: modernizando a arquitertura  de sua aplicação

isolando regra de negócio

php estruturado

Page 25: modernizando a arquitertura  de sua aplicação

// 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

Page 26: modernizando a arquitertura  de sua aplicação

interagindo

regras de negócio com a apresentação

php estruturado

Page 27: modernizando a arquitertura  de sua aplicação

// 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

Page 28: modernizando a arquitertura  de sua aplicação

// 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

Page 29: modernizando a arquitertura  de sua aplicação

// 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

Page 30: modernizando a arquitertura  de sua aplicação

// 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

Page 31: modernizando a arquitertura  de sua aplicação

isolando layout

php estruturado

Page 32: modernizando a arquitertura  de sua aplicação

// template/layout.php

<!DOCTYPE html><html> <head> <title><?php echo $title ?></title> </head> <body> <?php echo $content ?> </body></html>

layout padrão

php estruturado

Page 33: modernizando a arquitertura  de sua aplicação

// template/wishlist/list.php

<?php $title = 'My Wish List' ?>

define o título da página

php estruturado

Page 34: modernizando a arquitertura  de sua aplicação

// 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

Page 35: modernizando a arquitertura  de sua aplicação

// 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

Page 36: modernizando a arquitertura  de sua aplicação

front controller

php estruturado

Page 37: modernizando a arquitertura  de sua aplicação

sem um front controller

GET /[email protected]

com index.php como um front controller

GET /index.php/wishlist/[email protected]

com regras de sobrescrita no servidor web

GET /wishlist/[email protected]

php estruturado

Page 38: modernizando a arquitertura  de sua aplicação

// 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

Page 39: modernizando a arquitertura  de sua aplicação

// 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

Page 40: modernizando a arquitertura  de sua aplicação

// 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

Page 41: modernizando a arquitertura  de sua aplicação

// 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

Page 42: modernizando a arquitertura  de sua aplicação

autoload

php estruturado

Page 43: modernizando a arquitertura  de sua aplicação

// 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 estruturadoautoload

Page 44: modernizando a arquitertura  de sua aplicação

php estruturado

Page 45: modernizando a arquitertura  de sua aplicação

{ "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

Page 46: modernizando a arquitertura  de sua aplicação

$ composer dump-autoload

// public/index.php

require_once __DIR__ . '/../vendor/autoload.php';

php estruturadoautoload

Page 47: modernizando a arquitertura  de sua aplicação

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

Page 48: modernizando a arquitertura  de sua aplicação

php orientado a objetos

Page 49: modernizando a arquitertura  de sua aplicação

código auto explicativo

facilidade no crescimento

testes automatizados

php orientado a objetos

Page 50: modernizando a arquitertura  de sua aplicação

testes automatizados

php orientado a objetos

Page 51: modernizando a arquitertura  de sua aplicação

garantem regras conhecidas

auxiliam na refatoração

não evitam bugs

testes automatizados

php orientado a objetos

Page 52: modernizando a arquitertura  de sua aplicação

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

Page 53: modernizando a arquitertura  de sua aplicação

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::testUpdateProductFailedFailed asserting that exception of type "ProductException" is thrown.

FAILURES!Tests: 59, Assertions: 125, Failures: 1.

testes automatizados

php orientado a objetos

Page 54: modernizando a arquitertura  de sua aplicação

não confie em arrays

evite abreviações

php orientado a objetos

Page 55: modernizando a arquitertura  de sua aplicação

/*** 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

Page 56: modernizando a arquitertura  de sua aplicação

objetos de valor

php orientado a objetos

Page 57: modernizando a arquitertura  de sua aplicação

objetos simples

encapsulam tipos primitivos

representam o valor

objetos de valor

php orientado a objetos

Page 58: modernizando a arquitertura  de sua aplicação

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

Page 59: modernizando a arquitertura  de sua aplicação

entidades

php orientado a objetos

Page 60: modernizando a arquitertura  de sua aplicação

são mutáveis

tem identificador

entidades

php orientado a objetos

Page 61: modernizando a arquitertura  de sua aplicação

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

Page 62: modernizando a arquitertura  de sua aplicação

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 umobjeto Item?

entidades

php orientado a objetos

Page 63: modernizando a arquitertura  de sua aplicação

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 umobjeto Item?

Produtos Presente

entidades

php orientado a objetos

Page 64: modernizando a arquitertura  de sua aplicação

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

Page 65: modernizando a arquitertura  de sua aplicação

repositórios

php orientado a objetos

Page 66: modernizando a arquitertura  de sua aplicação

camada de persistência

estratégia de armazenamento

repositórios

php orientado a objetos

Page 67: modernizando a arquitertura  de sua aplicação

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

Page 68: modernizando a arquitertura  de sua aplicação

namespace Develop\Business\Application\ProductWishlist\Repositories;

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

Page 69: modernizando a arquitertura  de sua aplicação

namespace Develop\Business\Application\ProductWishlist\Repositories;

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

Page 70: modernizando a arquitertura  de sua aplicação

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

Page 71: modernizando a arquitertura  de sua aplicação

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

Page 72: modernizando a arquitertura  de sua aplicação

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

Page 73: modernizando a arquitertura  de sua aplicação

serviços

php orientado a objetos

Page 74: modernizando a arquitertura  de sua aplicação

camada de operação

orquestra os objetos

define o que fazer

serviços

php orientado a objetos

Page 75: modernizando a arquitertura  de sua aplicação

adicionando um item na lista de desejos

serviços

php orientado a objetos

Page 76: modernizando a arquitertura  de sua aplicação

$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

Page 77: modernizando a arquitertura  de sua aplicação

$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

Page 78: modernizando a arquitertura  de sua aplicação

$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();}

criandoobjeto de serviço

adicionando um item na lista de desejos

php orientado a objetos

Page 79: modernizando a arquitertura  de sua aplicação

$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();}

executandoo serviço

adicionando um item na lista de desejos

php orientado a objetos

Page 80: modernizando a arquitertura  de sua aplicação

$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

Page 81: modernizando a arquitertura  de sua aplicação

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

Page 82: modernizando a arquitertura  de sua aplicação

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 objetoscomo adicionar um item na lista de desejos

Page 83: modernizando a arquitertura  de sua aplicação

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 objetoscomo adicionar um item na lista de desejos

Page 84: modernizando a arquitertura  de sua aplicação

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 objetoscomo adicionar um item na lista de desejos

Page 85: modernizando a arquitertura  de sua aplicação

serviços

notificar usuário quando

um item estiver disponível

php orientado a objetos

Page 86: modernizando a arquitertura  de sua aplicação

// 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

Page 87: modernizando a arquitertura  de sua aplicação

// 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

Page 88: modernizando a arquitertura  de sua aplicação

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

Page 89: modernizando a arquitertura  de sua aplicação

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

Page 90: modernizando a arquitertura  de sua aplicação

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

Page 91: modernizando a arquitertura  de sua aplicação

injeção de dependência

php orientado a objetos

Page 92: modernizando a arquitertura  de sua aplicação

princípio da inversão de dependência

dependências configuráveis

injeção de dependência

php orientado a objetos

Page 93: modernizando a arquitertura  de sua aplicação

Respect/Config

injeção de dependência

php orientado a objetos

Page 94: modernizando a arquitertura  de sua aplicação

// 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

Page 95: modernizando a arquitertura  de sua aplicação

// public/index.php

require_once __DIR__ . '/../config/app.php';require_once __DIR__ . '/../vendor/autoload.php';

$configFile = __DIR__ . '/../config/app.ini';

$container = new Respect\Config\Container($configFile);

if ('/index.php/wishlist/add' === $uri /* other validations */) { wishlistAddAction($container, $_GET['email'], $_POST);}

injeção de dependência

php orientado a objetos

Page 96: modernizando a arquitertura  de sua aplicação

// public/index.php

require_once __DIR__ . '/../config/app.php';require_once __DIR__ . '/../vendor/autoload.php';

$configFile = __DIR__ . '/../config/app.ini';

$container = new Respect\Config\Container($configFile);

if ('/index.php/wishlist/add' === $uri /* other validations */) { wishlistAddAction($container, $_GET['email'], $_POST);}

injeção de dependência

php orientado a objetos

Page 97: modernizando a arquitertura  de sua aplicação

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

Page 98: modernizando a arquitertura  de sua aplicação

eventos

php orientado a objetos

Page 99: modernizando a arquitertura  de sua aplicação

mecanismo de inversão de controle

comunicação assíncrona

baixo acoplamento

eventos

php orientado a objetos

Page 100: modernizando a arquitertura  de sua aplicação

symfony/event-dispatcher

eventos

php orientado a objetos

Page 101: modernizando a arquitertura  de sua aplicação

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

Page 102: modernizando a arquitertura  de sua aplicação

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

Page 103: modernizando a arquitertura  de sua aplicação

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

Page 104: modernizando a arquitertura  de sua aplicação

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

Page 105: modernizando a arquitertura  de sua aplicação

estrutura

php orientado a objetos

Page 106: modernizando a arquitertura  de sua aplicação

business

services

application

webdevices

use

inte

rfac

e

databaseEx

tern

al I

nter

face

s

camadas

php orientado a objetos

Page 107: modernizando a arquitertura  de sua aplicação

// 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

Page 108: modernizando a arquitertura  de sua aplicação

// 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

Page 109: modernizando a arquitertura  de sua aplicação

developing-for-business

├── cli

│ └── wishlist_notification.php

├── data

│ └── business.db

├── lib

│ ├── dbconn.php

│ └── functions.php

└── public

└── wishlist.php

estrutura php puro

Page 110: modernizando a arquitertura  de sua aplicação

Develop\Business

└── Application

├── Product

│ ├── Controllers

│ └── Repositories

└── ProductWishlist

├── Controllers

├── Resolver

├── Listeners

└── Repositories

Develop\Business

├── Product

│ ├── Events

│ ├── Exceptions

│ ├── Intentions

│ ├── Repositories

│ └── UseCases

└── Wishlist

├── Exceptions

├── Intentions

├── ItemResolver.php

├── Repositories

└── UseCases

estrutura php orientado a objetos

Page 111: modernizando a arquitertura  de sua aplicação

conclusãosaia da zona de conforto

Page 112: modernizando a arquitertura  de sua aplicação

interaja com a comunidade

conclusão

Page 113: modernizando a arquitertura  de sua aplicação

automatize tarefas repetitivas

conclusão

Page 114: modernizando a arquitertura  de sua aplicação

domain driven design

conclusão

Page 115: modernizando a arquitertura  de sua aplicação

domain specific language

conclusão

Page 116: modernizando a arquitertura  de sua aplicação

princípio S.O.L.I.D.

conclusão

Page 117: modernizando a arquitertura  de sua aplicação

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

Page 118: modernizando a arquitertura  de sua aplicação

Life's too short for bad softwareLew Cirne, New Relic