DDD in PHP

2.675 visualizações

Publicada em

DDD in PHP Phpexperience brasil 2015

Publicada em: Tecnologia
  • Seja o primeiro a comentar

DDD in PHP

  1. 1. Domain-Driven Design além da teoria Paulo Victor L. L. Gomes
  2. 2. Presentation licensed by Share - Keep license - noncommercial http://creativecommons.org/licenses/by-nc-sa/3.0/
  3. 3. Domain-Driven Design? Domain-Driven Design é uma abordagem para o Desenvolvimento de Software que estabelece uma forte ligação entre a implementação e o modelo evolutivo dos conceitos de negócio. Implementação X Negócios
  4. 4. Fundamentação Onde colocar a regra de negócio?
  5. 5. Primeira resposta “Vai escrevendo código ai, quando precisar coloque na camada de apresentação, no banco de dados nos controles, modelos, na configuração do webserver e não esquece do xml e aquele if maroto no APPLICATION_ENV”
  6. 6. Resultado
  7. 7. Fundamentação Encapsule, Daniel San
  8. 8. Orientação a Objetos?
  9. 9. Orientação a Objetos Meu framework já usa Orientação a Objetos. Esse papo é muito antigo e eu já superei esse problema.
  10. 10. Orientação a Objetos Olha meu código... public function imagodAction() { $local=VdModel::getLocalStorageAdapter();$items=$purchase->getItemCollection()->getItems();$Items=$this- >cart->getItems();$index=array();$catalogHelper=newGodHelper();$quantityCartByidentifier=array(); $itemsRemove=array();foreach($itemsas$salespurchaseItem){$quantityCartByidentifier[$salespurchaseItem- >getidentifier()]=(isset($quantityCartByidentifier[$salespurchaseItem->getidentifier()])? $quantityCartByidentifier[$salespurchaseItem->getidentifier()]+1:1);foreach($itemsas$salespurchaseItem){if ($salespurchaseItem->getBundleidentifier()&&!isset($index[$salespurchaseItem->getBundleidentifier()])) {'uniqueAttributes'=>CatalogHelper::getSimpleUniqueAttributes($product,$salespurchaseItem- >getidentifier()),'color_cart'=>isset($product['meta']['color_family'])?$product['meta'] ['color_family']:'','shipment_delivery_time'=>$salespurchaseItem->getShipmentTotalDeliveryTime(),)), 'bundleproducts'=>array($simples[$salespurchaseItem->getidentifier()]=>(isset($simples[$salespurchaseItem- >getidentifier()])?$simples[$salespurchaseItem->getidentifier()]+1:1)),);$bundleproduct=$local->get ('product',(strstr($salespurchaseItem->getBundleidentifier(),'-',true))); //resolveproducturable$product=$local->get('product',($simples[$salespurchaseItem->getidentifier()])); $simple=$product['simples'][$salespurchaseItem->getidentifier()];$identifierHandle=$salespurchaseItem- >getBundleidentifier();if(isset($bundleproduct['products'][$simples[$salespurchaseItem->getidentifier()]] ['quantity_items'])){$quantityItems=$bundleproduct['products'][$simples[$salespurchaseItem- >getidentifier()]]['quantity_items'];}else{$quantityItems=1;$itemsRemove[]=$salespurchaseItem- >getBundleidentifier();}$index[$identifierHandle]['salespurchaseItem']->setShipmentTotalDeliveryTime(max ($index[$identifierHandle]['salespurchaseItem']->getShipmentTotalDeliveryTime(),$salespurchaseItem- >getShipmentTotalDeliveryTime()));$index[$identifierHandle]['stock']=min($simple['meta']['quantity'],$index [$identifierHandle]['stock']);$index[$identifierHandle]['cart_rule_discount']+=$salespurchaseItem- >getCartRuleDiscount();if(isset($index[$identifierHandle]['bundleproducts'][$simples[$salespurchaseItem- >getidentifier()]])){if($index[$identifierHandle]['bundleproducts'][$simples[$salespurchaseItem- >getidentifier()]]<$quantityItems){$index[$identifierHandle]['salespurchaseItem']->setUnitPrice($index [$identifierHandle]['salespurchaseItem']->getUnitPrice()+$salespurchaseItem->getUnitPrice());$index [$identifierHandle]['salespurchaseItem']->setPaidPrice($index[$identifierHandle]['salespurchaseItem']-
  11. 11. Orientação a Objetos Quando pensamos em POO logo pensamos em Classes, Encapsulamento, Polimorfismo, Herança... POO é mais que isso, a essência da POO é alinhamento do código com o negócio, reutilização, mínimo de acoplamento, linguagem natural...
  12. 12. Como eu uso? De onde eu começo? sudo apt-get install ddd (#sqn) Domain Driven Design
  13. 13. O desafio proposto... Comunicação entre equipe de produto e desenvolvimento
  14. 14. O mundo como ele é...
  15. 15. Linguagem Ubíqua Definições de Ubíqua “O termo foi usado pela primeira vez pelo cientista Norte-Americano Mark Weiser em 1988 e publicado em 1991 no seu artigo The Computer for the 21st Century” “termo usado para descrever a onipresença da informática no cotidiano das pessoas” “Computação ubíqua tem como objetivo tornar a interação homem computador invisível, ou seja, integrar a informática com as ações e comportamentos naturais das pessoas” Para que um software atenda um domínio, é necessário que se estabeleça, em primeiro lugar, uma linguagem Ubíquia ou seja, linguagem comum, com termos bem definidos, que fazem parte do domínio do negócio e que são usados por todas as pessoas que fazem parte do processo de desenvolvimento.
  16. 16. Projeto Dirigido pelo Modelo (Model Driven Design – MDD). A ideia por trás de MDD é a de que o seu modelo abstrato deve ser uma representação perfeita do seu domínio. MDD – Model Driven Design UML ajuda muito nessa fase mas, use com cuidado!
  17. 17. Blocos de Construção
  18. 18. Blocos de Construção
  19. 19. DDD na prática Camada de domínio. Para modelar essa parte, utilizamos alguns Padrões propostos em DDD. Chamados de blocos de construção, utilizados para representar nosso modelo abstrato. Esses blocos podem ser: Entidades - classes de objetos que necessitam de uma identidade. Objetos de Valores - objetos que só carregam valores, mas que não possuem distinção de identidade. Agregados - compostos de Entidades ou Objetos de Valores que são encapsulados numa única classe Fábricas - classes responsáveis pelo processo de criação dos Agregados ou dos Objetos de Valores Serviços - classes que contêm lógica de negócio, mas que não pertencem a nenhuma Entidade ou Objetos de Valores. Repositórios - classes responsáveis por administrar o ciclo de vida dos outros objetos, normalmente Entidades, Objetos de Valor e Agregados.
  20. 20. DDD na prática Camada de domínio. Para modelar essa parte, utilizamos alguns Padrões propostos em DDD. Chamados de blocos de construção, utilizados para representar nosso modelo abstrato. Esses blocos podem ser: Entidades - classes de objetos que necessitam de uma identidade. Objetos de Valores - objetos que só carregam valores, mas que não possuem distinção de identidade. Agregados - compostos de Entidades ou Objetos de Valores que são encapsulados numa única classe Fábricas - classes responsáveis pelo processo de criação dos Agregados ou dos Objetos de Valores Serviços - classes que contêm lógica de negócio, mas que não pertencem a nenhuma Entidade ou Objetos de Valores. Repositórios - classes responsáveis por administrar o ciclo de vida dos outros objetos, normalmente Entidades, Objetos de Valor e Agregados.
  21. 21. Objeto de Valor (Value Object) Muitos objetos não possuem nenhuma identidade conceitual. Esses objetos descrevem alguma característica de alguma coisa.
  22. 22. Características - Medir - Quantificar - Descrever Imutabilidade “This is one of the most important aspects of a Value Object to grasp. Object values should not be able to be altered over their life-time. Because of this immutability, Value Objects are easy to reason, test and are free of undesired/unexpected side-effects.” (Carlos Buenosvinos, Christian Soronellas and Keyvan Akbary DDD in PHP)
  23. 23. Objetos de Valor x Entidades
  24. 24. class Currency { private $isoCode; public function __construct($anIsoCode) { $this->setIsoCode($anIsoCode); } private function setIsoCode($anIsoCode) { if (!preg_match('/^[A-Z]{3}$/', $anIsoCode)) { throw new InvalidArgumentException(); } $this->isoCode = $anIsoCode; } public function isoCode() { return $this->isoCode; } }
  25. 25. class Money { private $amount; private $currency; public function __construct($anAmount, Currency $aCurrency) { $this->setAmount($anAmount); $this->setCurrency($aCurrency); } private function setAmount($anAmount) { $this->amount = (int) $anAmount; } private function setCurrency(Currency $aCurrency) { $this->currency = $aCurrency; } }
  26. 26. class Money { /……/ public static function fromMoney(Money $aMoney) { return new self( $aMoney->amount(), $aMoney->currency() ); } public static function ofCurrency(Currency $aCurrency) { return new self(0, $aCurrency); } }
  27. 27. class Money { /……/ public function increaseAmountBy($anAmount) { return new self( $this->amount() + $anAmount, $this->currency() ); } public function add(Money $money) { if (!$money->currency()->equals($this->currency())) { throw new InvalidArgumentException(); } return new self( $money->amount() + $this->amount(), $this->currency() ); } }
  28. 28. $a = new Currency('BRL'); $b = new Currency('BRL'); var_dump($a == $b); // bool(true) var_dump($a === $b); // bool(false) $c = new Currency('EUR'); var_dump($a == $c); // bool(false) var_dump($a === $c); // bool(false)
  29. 29. class MoneyTest extends PHPUnit_Test_TestCase { Const BRAZIL_CURRENCY = "BRL"; public function testCopiedMoneyShouldRepresentSameValue() { $aMoney = new Money(100, new Currency(self::BRAZIL_CURRENCY)); $copiedMoney = Money::fromMoney($aMoney); $this->assertTrue($aMoney->equals($copiedMoney)); } public function testOriginalMoneyShouldNotBeModifiedOnAddition() { $aMoney = new Money(100, new Currency(self::BRAZIL_CURRENCY)); $aMoney->add(new Money(20, new Currency(self::BRAZIL_CURRENCY))); $this->assertEquals(100, $aMoney->amount()); } public function testMoneysShouldBeAdded() { $aMoney = new Money(100, new Currency(self::BRAZIL_CURRENCY)); $newMoney = $aMoney->add(new Money(20, new Currency(self::BRAZIL_CURRENCY))); $this->assertEquals(120, $newMoney->amount()); } }
  30. 30. Persistindo Objetos de Valor Objetos de valor não são persistidos por conta própria, até por que eles não possuem identificação. Geralmente um Objeto de Valor é gravado como atributos de um agregado que possue identificação lógica no sistema.
  31. 31. <?php class Product { private $productId; private $name; private $price; public function __construct( $aProductId, $aName, Money $aPrice ) { $this->setProductId($aProductId); $this->setName($aName); $this->setPrice($aPrice); } // ... }
  32. 32. <?php interface ProductRepository { /** * @param Product $aProduct * @return bool */ public function add(Product $aProduct); /.../ }
  33. 33. $productRepository = $this->get('repository.product'); $product = new Product( $productRepository->nextIdentity(), 'Camiseta PHP Experience 2015', new Money(999, new Currency('BRL')) ); $productRepository->add($product);
  34. 34. class DbalProductRepository extends DbalRepository implements ProductRepository { public function add(Product $aProduct) { $sql = 'INSERT INTO products VALUES (?, ?, ?, ?)'; $stmt = $this->connection()->prepare($sql); $stmt->bindValue(1, $aProduct->id()); $stmt->bindValue(2, $aProduct->name()); $stmt->bindValue(3, $aProduct->price()->amount()); $stmt->bindValue(4, $aProduct->price()->currency()->isoCode()); $stmt->execute(); // ... } }
  35. 35. class DbalProductRepository extends DbalRepository implements ProductRepository { public function productOfId($anId) { $sql = 'SELECT * FROM products WHERE id = ?'; $stmt = $this->connection()->prepare($sql); $stmt->bindValue(1, $anId); $res = $stmt->execute(); // ... return new Product( $row['id'], $row['name'], new Money( $row['price_amount'], new Currency( $row['price_currency'] ) ) ); } }
  36. 36. Entidade (Entity) Muitos objetos não são fundamentalmente definidos por seus atributos, mas sim por uma linha de continuidade e identidade
  37. 37. class Person { private $identificationNumber; private $firstName; private $lastName; public function __construct($anIdentificationNumber, $aFirstName, $aLastName) { $this->identificationNumber = $anIdentificationNumber; $this->firstName = $aFirstName; $this->lastName = $aLastName; } public function identificationNumber() { return $this->identificationNumber; } public function firstName() { return $this->firstName; } public function lastName() { return $this->lastName; } }
  38. 38. namespace DomainEntity; class Product { private $id; private $name; private $description; private $ean; private $price; private $measure; private $category; private $specification; public function __construct(Category $category, VOSpecification $specification, VOPrice $price, VOMeasure $measure, $id) { $this->category = $category; $this->id = $id; $this->measure = $measure; $this->price = $price; $this->specification = $specification; } }
  39. 39. Pequenos exemplos sobre isolamento de domínio
  40. 40. Pequena explicação BISO BUSINESS ISOLATION github.com/pvgomes/zend2biso github.com/pvgomes/symfony2biso github.com/pvgomes/biso
  41. 41. Building blocks
  42. 42. Referência
  43. 43. Referência Domain-Driven Design in PHP Real examples written in PHP showcasing DDD Architectural Styles, Tactical Design, and Bounded Context Integration. Carlos Buenosvinos, Christian Soronellas and Keyvan Akbary http://leanpub.com/ddd-in-php
  44. 44. Perguntas?

×