Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Boas práticas com PHP: novidades, clean code e um pouco de arquitetura

7bb3a66a199daec275d5ad339724c754?s=47 Junior Grossi
September 26, 2019

Boas práticas com PHP: novidades, clean code e um pouco de arquitetura

O PHP tem mudado muito nos últimos anos. Neste workshop vamos passar brevemente pelas principais mudanças dos últimos 10 anos e discutir algumas boas práticas para tornar seu código mais limpo e aumentar sua produtividade, além de navegar um pouco no que tem de mais atual em se tratando de arquitetura de software.

7bb3a66a199daec275d5ad339724c754?s=128

Junior Grossi

September 26, 2019
Tweet

More Decks by Junior Grossi

Other Decks in Programming

Transcript

  1. BOAS PRÁTICAS COM PHP novidades, clean code e um pouco

    de arquitetura
  2. Sou Junior Grossi twitter.com/junior_grossi github.com/jgrossi

  3. Paciência!

  4. https://github.com/corcel/corcel

  5. PHPMG Conference 2019 21/09/2019 - Belo Horizonte, MG https://conf.phpmg.com

  6. None
  7. None
  8. https://glofox.com/careers

  9. ◽ 2004 php ◽ 2016 ◽

  10. PARTE 1 PHP ANTES E DEPOIS Os últimos 10 anos

    da linguagem mais usada na Web!
  11. PHP ARCHITECT Nov/2018 | Volume 17 | Issue 11

  12. PHP EM 2019 Linguagem mais usada na Web (~80%) Só

    o WordPress é responsável por ~36% Muito problema pra resolver (mais empregos)
  13. None
  14. PHP 5.3 (2009) O DIVISOR DE ÁGUAS NAMESPACES + LAMBDA

    FUNCTIONS/CLOSURES (Mudanças no processo interno de releases do PHP)
  15. REQUEST FOR COMMENTS (RFC) https://wiki.php.net/rfc

  16. NAMESPACES Classes não podiam ter o mesmo nome HtmlPrinter, Zend_HtmlPrinter

    class Zend_HtmlPrinter { public function print(); }
  17. namespace Grossi\Talks; use Foo\Exporter\Exporter; use Zend\Html\Exporter as ZendExporter; class PhpTalk

    { public function export() { $fooExporter = new Exporter(); $zendExporter = new ZendExporter(); // ... } } https://wiki.php.net/rfc/namespacecurlies
  18. LAMBDA FUNCTIONS/CLOSURES Antes do PHP 5.3 A partir do PHP

    5.3 $array = array_map('append_x', $array); function append_x($item) { return $item . 'x'; } $array = array_map(function ($item) { return $item . 'x'; }, $array);
  19. Nova geração de frameworks (surgimento dos primeiros micro-frameworks) (execução tardia)

    $router­>get('/users/{id}', function ($id) { return User::find($id); }); $function = function ($word) { echo $word . ' World!'; } $function('Hello'); // "Hello World!"
  20. 2012 PHP 5.4 + COMPOSER ANO DAS MAIORES MUDANÇAS (Mudou

    de vez a comunidade PHP)
  21. TRAITS trait Flyable { public function fly() { // Go,

    fly! } } trait Walkable { public function walk() { // Go, walk! } } class Bird { use Flyable, Walkable; } class Chicken { use Walkable; } $bird = new Bird(); $chicken = new Chicken(); $bird­>walk(); $bird­>fly(); $chicken­>walk();
  22. SHORTENED ARRAY SYNTAX Antes do PHP 5.4 Depois do PHP

    5.4 $numbers = array(1, 2, 3); $associative = array('name' => 'Junior', 'age' => 34); $numbers = [1, 2, 3]; $associative = ['name' => 'Junior', 'age' => 34];
  23. BUILT-IN WEB SERVER Não é necessário mais um Web server

    pra desenvolvimento > php ­S localhost:8000
  24. COMPOSER Package Manager oficial do PHP http://getcomposer.org

  25. COMPOSER Resolveu o problema do Ctr C + Ctr V

    + controle de versões
  26. COMPOSER Resolveu o problema dos require > composer require cakephp/database

    require 'database.php'; require 'pdf.php'; require 'mail.php'; require 'image.php'; require 'sms.php'; $database = db_query('SELECT * FROM users');
  27. /composer.json { "name": "jgrossi/corcel", "description": "Use WordPress backend with Laravel

    or any PHP framework", "homepage": "http://github.com/corcel/corcel", "authors": [ { "name": "Junior Grossi", "email": "juniorgro@gmail.com" } ], "require": { "php": ">=7.1.3", "illuminate/database": "5.7.*", "hautelook/phpass": "0.3.*", "thunderer/shortcode": "^0.6.2" }, "require­dev": { "phpunit/phpunit": "^7.0", "mockery/mockery": "^1.0" }, "autoload": { "psr­4": { "Corcel\\": "src/", "Corcel\\Tests\\": "tests/" } } }
  28. AUTOLOADING + NAMESPACES use Corcel\Model\Post;

  29. PACKAGIST http://packagist.org

  30. PHP-FIG PSR (PHP STANDARD RECOMMENDATION) code style, autoload, interfaces padronizaram

    a toda
  31. https://www.php-fig.org

  32. PSR-7 PSR-11 namespace MyFramework\Http; use Psr\Http\Message\RequestInterface; class Request implements RequestInterface

    { } namespace MyFramework\Container; use Psr\Container\ContainerInterface; class Container implements ContainerInterface { }
  33. PHP 5.5 E 5.6 ANTES DA GRANDE MUDANÇA (2013 e

    2014) Adiciona scalar class name resolution via ::class Adiciona finally para exceptions Melhoria de performance (Zend OPcache) Outras mudanças...
  34. PHP 7 TUDO NOVO, DE NOVO!

  35. PERAÍ, E O PHP 6?

  36. https://wiki.php.net/rfc/php6

  37. PHP 7 (2015) Nova Zend Engine (v3) 2x mais rápido

    que PHP 5 50% menos de consumo de memória
  38. None
  39. None
  40. PHP 7.0 UNIFORM VARIABLE SYNTAX // Before $foo = new

    Foo(); $baz = $foo­>bar(); // After $baz = (new Foo())­>bar(); // Before $foo = $foo­>bar(); echo $foo[0]; // After echo $foo­>bar()[0];
  41. PHP 7.0 NULL COALESCE OPERATOR: ?? // Before $age =

    isset($data['age']) ? $data['age'] : 100; // After $age = $data['age'] ?? 100;
  42. PHP 7.0 ⭐ RETURN TYPE DECLARATIONS ⭐ ⭐ SCALAR TYPE

    DECLARATIONS ⭐ (opcional) // Before public function create($sum, $title) { // your code here } // After public function create(float $sum, string $title): float { // your code here }
  43. STRICT TYPES = 1 declare(strict_types=1); namespace Foo\Printer; class CsvPrinter implements

    PrinterInterface { public function __construct(string $foo, float $bar) { // ... } }
  44. PHP 7.0 GROUP USE DECLARATIONS // Before use Package\Http\Request; use

    Package\Http\Response; use Package\Http\Middleware; use Package\Http\BaseController as Controller; // After use Package\Http\{ Request, Response, BaseController as Controller };
  45. PHP 7.1, 7.2 E 7.3 void return type class constant

    visibility modifiers nullable types the object parameter and return type Libsodium extension abstract method overriding
  46. class User { private const TYPE_ADMIN = 'admin'; protected const

    TYPE_MEMBER = 'member'; public const TYPE_GUEST = 'guest'; } public function save(object $object, ?int $age): void { // do something and return nothing }
  47. NOVIDADES: PHP 7.4 NOV/2019 Preloading* Short closures Typed properties Improved

    type variance The null coalescing assignment operator muito mais!
  48. PHP 7.4 SHORT CLOSURES array_map(function (User $user) use ($prefix) {

    return $prefix . $user­>id; }, $users) array_map(fn(User $user) => $prefix . $user­>id, $users)
  49. PHP 7.4 TYPED PROPERTIES ANTES class Foo { /** @var

    int $bar */ private $bar; /** @var callable $bar */ private $function; /** @var string|null $bar */ protected $baz; /** @var array $bar */ public $list; }
  50. PHP 7.4 TYPED PROPERTIES DEPOIS class Foo { private int

    $bar = 4; private callable $function; protected ?string $baz = null; public array $list = [1, 2, 3]; }
  51. PHP 8 ❤ JIT (just in time) compiler (vídeo do

    Zeev)
  52. None
  53. CONSIDERAÇÕES FINAIS PHP é uma das linguagens mais maduras Excelente

    performance (e vai melhorar!) Desenvolvimento muito rápido!
  54. PHP DO JEITO CERTO http://br.phptherightway.com/

  55. PARTE 2 CLEAN CODE resumão pra quem comprou mas não

    leu o livro!
  56. LIVRO Clean Code A Handbook of Agile So ware Cra

    smanship Robert C. Martin (Uncle Bob)
  57. AGENDA Resumo dos principais tópicos Não dá pra cobrir tudo

    Focado em PHP quando possível! Alguns detalhes vão ser explicados mais à frente
  58. CAPÍTULO 1 Clean Code "You are reading this book for

    two reasons. First, you are a programmer. Second, you want to be a better programmer. Good. We need better programmers."
  59. (bootstrap time!)

  60. "CODE-SENSE" "A programmer without "code-sense" can look at a messy

    module and recognize the mess but will have no idea what to do about it. A programmer with "code-sense" will look at a messy module and see options and variations." Uncle Bob
  61. ALGUNS PONTOS Passamos mais tempo lendo código Escrever código limpo

    requer disciplina O "code-sense" é a chave! Alguns de nós nascem com o "code-sense" Outros só com a prática!
  62. CAPÍTULO 2 Meaningful Names "Names are everywhere in so ware.

    We name our variables, our functions, our arguments, classes, and packages. We name our source files and the directories that contain them. We name and name and name."
  63. EXPRESSE INTENÇÃO AO DAR NOMES Use nomes pronunciáveis / Evite

    abreviações
  64. class DtaRcrd102 { private DateTime $genymdhsm; private DateTime $modymdhms; private

    string $pszqint = "102"; } class Customer { private DateTime $generationTimestamp; private DateTime $modificarionTimestamp; private string $recordId = "102"; }
  65. NOMES "BUSCÁVEIS" / CONSTANTES for ($i = 0; $i <

    5; $i++) { // ... } for ($i = 0; $i < WORK_DAYS_PER_WEEK; $i++) { // ... }
  66. EVITE PREFIXOS/SUFIXOS DESNECESSÁRIOS $txtFirstName = $controller­>request()­>get('txt_FirstName');

  67. INTERFACES E IMPLEMENTAÇÕES Evitar informação demais pro usuário (dev) (estou

    passando uma interface ou classe concreta?) PSR Naming Conventions | Symfony UserInterface, AbstractResolver, ReusableTrait
  68. EVITE O "MAPA MENTAL" Não obrigue o usuário a tentar

    entender o que está escrito Buscar entender pelo contexto é muito mais demorado!
  69. NOMES DE CLASSES "Classes and objects should have noun or

    noun phrase names like Customer, WikiPage, Account, and AddressParser. Avoid words like Manager, Processor, Data, or Info in the name of a class. A class name should not be a verb." (resumindo: nome de classe = substantivo)
  70. NOMES DE MÉTODOS Devem ser verbos Devem ser declarativos (ações)

    Accessors (get), Mutators (set) e predicates (is)
  71. UMA PALAVRA POR CONCEITO Nunca misture palavras de conceitos similares

    fetch, retrieve, get
  72. USE NOMES PRESENTES EM PADRÕES Todo dev sabe (ou deveria)

    saber Design Patterns Facilita o entendimento sobre a solução implementada AccountVisitor, ConsoleDecorator, UserFactory
  73. NÃO ADICIONE CONTEXTO DESNECESSÁRIO Contexto deve ficar no namespace Nome

    de classe deve resumir o que ela faz GSDAMailingAddress, GSDAAccountAddress GSDA\MailingAddress, GSDA\AccountAddress
  74. CAPÍTULO 3 Functions "In the early days of programming we

    composed our systems of routines and subroutines. Nowadays only the functions survives from those early days. Functions are the first line of organization in a any program."
  75. FUNÇÕES/MÉTODOS PEQUENOS Máximo 20 linhas. Se possível menos. Máximo 120

    caracteres por linha. Se possível 80.
  76. BLOCOS E INDENTAÇÃO Cada bloco de uma linha (chamada de

    método) Métodos com 1 ou 2 níveis de indentação foreach ($users as $user) { foreach ($user­>phoneNumbers() as $phoneNumber) { $this­>sendSmsToNumber($phoneNumber); } }
  77. FAÇA UMA COISA Devem fazer apenas uma coisa (e fazer

    bem) Nomes muito grande podem necessitar ser refatorados Palavras de alerta: And, Or, If
  78. "STEPDOWN RULE" Leitura fluente como texto if (!$user = $this­>findUser())

    { // ... } $this­>save($user); $user = $this­>findUser(); if (!$user) { // ... } $this­>save($user);
  79. private function something(): bool { return !$this­>foo() || $this­>bar(); }

    private function something(): bool { if (!$this­>foo()) { return false; } if ($this­>bar()) { return true; } return false; }
  80. switch Tolerados se aparecerem apenas uma vez Pensar em AbstractFactory

    se mais de uma vez Cuidado para não ferir SRP
  81. USE NOMES DESCRITIVOS Word's principle: "You know you are working

    on clean code when each routine turns out to be pretty much what you expected." Não tenha medo de escrever nomes longos Escreva exatamente o que está sendo feito
  82. ARGUMENTOS Nenhum é sempre melhor 1 ou 2 aceitáveis /

    3 deve ser evitado (aumento do número de argumentos dificulta escrever testes)
  83. "Flag Arguments" nunca (boolean) Deixa claro que faz mais de

    uma coisa Refatore para um método para cada coisa (argumento boolean exige mais de um caso de teste, sempre!)
  84. private function doSomething(string $foo, bool $bar): void { if ($bar)

    { // something } // ... }
  85. Encapsule argumentos em objetos (dá mais significado ao argumento) private

    function makeCircle(float $x, float $y): Circle { // ... } private function makeCircle(Point $point): Circle { // ... }
  86. Verbos e palavras-chave (dá mais significado ao argumento) public function

    find(Email $email): User { // ... } public function findUserByEmail(Email $email): User { // ... }
  87. CAPÍTULO 4 Comentários "Don't comment bad code - rewrite it."

    Brian W. Kernighan e P. J. Plaugher
  88. "Truth can only be found in one place: the code.

    Only the code can truly tell you what it does."
  89. None
  90. CONSIDERAÇÕES Remova comentários que não adicionam nada (docblock) Referências internas

    Críticas ou sugestões
  91. /** * Returns the day of the month. * *

    @return int the day of the month. */ public function getDayOfMonth(): int { return $this­>dayOfMonth; }
  92. None
  93. /** The first name */ private string $firstName; /** The

    last name */ private string $lastName; /* Added by Junior */ $response = new InputStreamResponse(); $response­>setBody($formatter­>getResultStream()); // $resultStream = $formatter­>getResultStream(); // $reader = new StreamReader($resultStram);
  94. CAPÍTULO 5 Formatação Visual importa sim!

  95. Escolhe um code style e o siga Agrupe blocos de

    linhas no mesmo contexto Declare variáveis próximo da utilização Variáveis de instância sempre no topo da classe $user = $this­>findUserByEmail($email); $event = new Event($user); $email = new WelcomeEmail(); $email­>to($user­>email()); $email­>send();
  96. Funções dependentes próximas Não alinhe horizontalmente class FitNesseExpediter implements ResponseSender

    { private Socket $socket; private InputStream $input; private OutputStream $output; private Request $request; private Response $response; private FitNesseContext $context; private float $requestParsingTimeLimit; protected float $requestProgress; }
  97. Indentação. Nem precisa falar, né?

  98. CAPÍTULO 6 Objetos e Estrutura de Dados "There is a

    reason that we keep our variables private. We don't want anyone else to depende on them. We want to keep the freedom to change their type or implementation on a whim or an impulse."
  99. Esconder implementação expões abstrações Manipular a essência dos dados por

    abstrações OOP permite adicionar novas classes sem mudar as existentes class HtmlParser implements ParserInterface { public function parse(): string { } }
  100. LEI DE DEMETER "Fale com amigos, não com estranhos." Encapsule

    o máximo possível. Exponha apenas o necessário.
  101. CAPÍTULO 7 Error Handling "...things can go wrong, and when

    they do, we as programmers are responsible for making sure that our code does what it needs to do."
  102. Exceptions sempre. Código de erro nunca! Escreva o bloco try/catch

    primeiro (facilita pensar em todas as possíveis exceções)
  103. Exceptions como primeira opção Trate a exceção na origem public

    function resolveUser(): User { $user = $this­>findInRequest(); if (!$user) { throw new UserNotFoundException(); } return $user; } try { $user = $resolver­>resolveUser(); } catch (UserNotFoundException $e) { return null; }
  104. DEFINA CONTEXTO public static function byEmail(string $email): self { return

    new self( sprintf('User not found with the email %s', $email) ); } throw UserNotFoundException::byEmail($user­>getEmail());
  105. NULL RETURN Evite retornar null Dispare exception e trate na

    origem Use Null Objects
  106. NÃO PASSE NULL COMO PARÂMETRO Perde consistência Adiciona complexidade (mais

    ifs)
  107. CAPÍTULO 9 Unit Tests "The Agile and TDD movements have

    encouraged many programmers to write automated unit tests, and more are joining their ranks every day. But in the mad rush to add testing to our discipline, many programmers have missed one of the more subtle, and important, points of writing good tests."
  108. AS 3 LEIS DO TDD 1. Escreva um teste que

    irá falhar. 2. Escreva o código para fazê-lo passar. 3. Repita o processo.
  109. CLEAN TESTS? Clean Code também para testes Crie "helpers" em

    forma de trait para adicionar funcionalidades extras trait JwtAuthenticationTrait { use HttpRequestsTrait; public function loginUser(User $user): void { $serializedToken = $this­>generateTokenForUser($user); $this­>request­>withHeader( 'HTTP_AUTHORIZATION', sprintf('Bearer %s', $serializedToken) ); } }
  110. DICAS PARA CLEAN TESTS Apenas um conceito por teste (cada

    caso possível é um novo teste)
  111. Teste com usuário admin + teste com não admin public

    function test_only_admins_can_change_user_type(): void {} public function test_admin_users_can_change_user_type(): void {} public function test_non_admin_users_cannot_change_user_type(): void
  112. "FIRST" RULE Fast: testes devem ser rápidos (evite DB pra

    testes - utilize mais in-memory objects) Independent: não devem compartilhar detalhes (um teste não pode influenciar resultado de outro) Repeatable: independentes de ambiente Self-Validating: ou passou ou não passou (boolean) Timely: escreva testes sempre antes (depois + difícil de testar)
  113. BÔNUS! Regra dos 3As (Arrange, Act, Assert) public function test_admin_users_can_change_user_type():

    void { // Arrange $admin = $this­>makeAdminUser(); $user = $this­>makeNormalUser(['type' => User::TYPE_MEMBER]); $this­>loginAsUser($admin); // Act $formatter = new Formatter(); $user = $formatter­>format($user); // Assert $this­>assertEquals(User::TYPE_MEMBER, $user­>getType()); }
  114. CAPÍTULO 10 Classes "Let's talk about Clean Classes"

  115. ENCAPSULAMENTO private por padrão protected quando necessário (herança ou testes)

    Foco sempre em encapsular primeiro! (use abstrações)
  116. CLASSES PEQUENAS Evite "God Classes" (SRP) Tamanho é determinado pelo

    nome! (evite Manager ou Processor) Caso feliz: ter um único método público (SRP) (facilita muito abstração)
  117. "COMPOSITION OVER INHERITANCE" Mais fácil com classes menores Nova funcionalidade?

    Nova classe + Dependency Injection da anterior!
  118. Nada de TokenManager ou coisas do tipo! OCP - Open-close

    Principle final class JwtTokenGenerator implements TokenGeneratorInterface {} final class IntegrationTokenGenerator implements TokenGeneratorInterface { private TokenGeneratorInterface $tokenGenerator; public function __construct(TokenGeneratorInterface $tokenGenerator) { $this­>tokenGenerator = $tokenGenerator; } }
  119. CONCLUSÕES Qualidade é um execício diário Comece a praticar (experiência)

    Melhoria de processos Diminuição de complexidade
  120. PARTE 3 CLEAN ARCHITECTURE um pouco de arquitetura não faz

    mal a ninguém!
  121. ARQUITETURA & DESIGN

  122. ARQUITETURA Visão em alto nível "Arquitetura de uma casa" Conexões

    e Comunicação de modo geral
  123. DESIGN Estruturas e decisões em baixo nível "Estilo dos móveis

    de uma casa" Design Patterns
  124. Robert C. Martin "O objetivo da arquitetura de so ware

    é minimizar os recursos humanos necessários para construir e manter um sistema."
  125. DESENVOLVIMENTO So ware difícil de manter tem vida curta Arquitetura

    facilita desenvolvimento para o time que o mantém
  126. Uma boa arquitetura começa com bons acordos Decisões em conjunto

    (time!) Comunicação é fundamental Mudar arquitetura é muito caro!
  127. MATURIDADE Às vezes grandes projetos começam pequenos Zero (ou pouca)

    arquitetura Problemas de arquitetura aparecem bem depois
  128. OBJETIVOS Fácil desenvolvimento / baixo custo Publicação rápida e fácil

    Diminuir custos com manutenção (custo mais caro)
  129. ARQUITETURA EM CAMADAS "Deixe opções em aberto" Camadas independentes Casos

    de uso independentes Comandos independentes
  130. SCREAMING ARCHITECTURE

  131. "Arquitetura fala por si só" Sobre o que é seu

    so ware? Olhando código! Leilão? Loja virtual? Reserva de hotéis? Ou uma aplicação Laravel? Zend? Symfony?
  132. "Uma boa arquitetura de so ware permite que decisões sobre

    frameworks, banco de dados, servidores web, e outros detalhes de ferramentas de ambiente, fiquem pra depois." Uncle Bob "Frameworks são opções a serem deixadas em aberto."
  133. QUAL O FOCO? (facilitar conversa com camada de negócios) "Uma

    boa arquitetura enfatiza os casos de uso e os dissocia de preocupações periférias."
  134. A Web é uma arquitetura?

  135. Não! Web é o mecanismo de entrega Sua arquitetura não

    deve se preocupar com entrega A Web é apenas um detalhe
  136. SOBRE TESTES

  137. Mais fácil escrever (e manter) "unit tests" em arquitetura totalmente

    baseada em casos de uso.
  138. PARA TESTAR: Você não precisa de framework Você não precisa

    de servidor web Você não precisa de banco de dados
  139. Lembrete: seus casos de uso são desacoplados! Seus casos de

    uso coordenam suas classes Entity. "Seus objetos Entity devem ser objetos simples que não possuem dependência nenhuma com frameworks ou bancos de dados."
  140. "Sua arquitetura deve dizer aos leitores sobre o sistema, não

    sobre o framework usado no sistema."
  141. CLEAN ARCHITECTURE

  142. ARQUITETURAS MAIS CONHECIDAS Domain-Driven Design (DDD) Hexagonal Architecture

  143. DOMAIN-DRIVEN DESIGN Implementing Domain-Driven Design (Vaughn Vernon)

  144. HEXAGONAL ARCHITECTURE "Hexagonal Architecture - Message-Oriented So ware Design" (Matthias

    Noback) https://youtu.be/K1EJBmwg9EQ
  145. CARACTERÍSTICAS COMUNS Independente de frameworks (framework-as-a-tool) Testável sem qualquer elemento

    externo Independente da UI (Web / Console) Independente de banco de dados Independente de qualquer agente externo
  146. "INDEPENDÊNCIA"

  147. https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html

  148. THE DEPENDENCY RULE "Dependências de código devem apontar somente para

    dentro, na direção de políticas de nível mais alto." Nada em um círculo interno pode saber alguma coisa concreta sobre algo em um círculo externo.
  149. THE DEPENDENCY RULE (AS 4 CAMADAS) 1. Entities (Enterprise Business

    Rules) 2. Use Cases (Application Business Rules) 3. Interface Adapters 4. Frameworks and Drivers
  150. 1. ENTITIES Encapsulamento de "Regras de Negócio" críticas Conjunto de

    classes e métodos
  151. 2. USE CASES Regras de Negócio específicas da aplicação Comandam

    o fluxo de dados ("de" e "para" as entidades) Mudanças nesta camada não devem afetar as entidades. (Command/Handler pattern)
  152. 3. INTERFACE ADAPTERS Conversão de dados externos para camadas internas

    ("Use Cases" e "Entities" - e vice-versa) MVC (Model, View, Controller) Ex: códigos SQL Nenhum código de camadas mais internas deve saber algo de banco de dados, por exemplo.
  153. 4. FRAMEWORKS AND DRIVERS Geralmente não se escreve código nesta

    camada Camada onde vão todos os detalhes ("Web é um detalhe", "banco de dados é um detalhe") Do lado de fora estes detalhes não podem fazer muito estrago. Uncle Bob "Não case com o framework!"
  154. ATRAVESSANDO LIMITES ⬆ Usando Dependency Inversion (SOLID) Exemplo: caso real

    - microserviço "tax"
  155. ATRAVESSANDO LIMITES Exemplo do que não se deve fazer Consulta

    ao ORM retorna um row object, não a representação do seu domínio. Você não pode passar esse row object para dentro do círculo, pois as camadas internas não devem saber nada sobre objetos das camadas de fora (BD). Doctrine ORM vs Eloquent ORM (Laravel)
  156. POR ONDE COMEÇAR? Command/Handler Pattern Command seria um "DTO" Handler

    seria o "Use Case"
  157. Command é um objeto simples imutável, que contem todos os

    inputs necessários para executar o "Handler" Handler é a execução do comando, com suas próprias dependências. Ele sabe que precisa do Command para processar.
  158. (1) Command para (1) Handler

  159. USE CASE: CREATE USER CreateUserCommand / CreateUserHandler

  160. 1. CONTROLLER ACTION POST /users UsersController@create()

  161. final class CreateUserAction { private CreateUserHandler $handler; public function __construct(CreateUserHandler

    $handler) { $this­>handler = $handler; } public function __invoke(RequestInterface $request): ResponseInterface { $user = $this­>handler­>handle( new CreateUserCommand( $request­>getAttribute('email'), $request­>getAttribute('firstName'), $request­>getAttribute('lastName'), $request­>getAttribute('password'), ) ); return new JsonResponse($user, 201); } }
  162. 2. COMMAND Classe simples que guarda os dados necessários para

    execução da ação. Classe imutável!
  163. final class CreateUserCommand implements CommandInterface { private string $email; private

    string $firstName; private string $lastName; private string $password; public function __construct( string $email, string $firstName, string $lastName, string $password ) { $this­>email = $email; $this­>firstName = $firstName; $this­>lastName = $lastName; $this­>password = $password; } // Getters: getEmail(), getFirstName(), getLastName(), getPassword() }
  164. 3. HANDLER Caso de uso propriamente dito Recebe o Command

    com todos os dados necessários
  165. final class CreateUserHandler implements HandlerInterface { private UserRepositoryInterface $userRepository; private

    PasswordEncrypterInterface $passwordEncrypter; public function __construct( UserRepositoryInterface $userRepository, PasswordEncrypterInterface $passwordEncrypter ) { $this­>userRepository = $userRepository; $this­>passwordEncrypter = $passwordEncrypter; } public function handle(CreateUserCommand $command): UserEntity { return $this­>userRepository­>create([ 'email' => $command­>getEmail(), 'firstName' => $command­>getFirstName(), 'lastName' => $command­>getLastName(), 'password' => $this­>passwordEncrypter­>encrypt($command­>getPassw ]); } }
  166. PRÓXIMO PASSO Adicionar um CommandBus (responsável por executar os Handlers)

    composer require league/tactician composer require illuminate/bus
  167. INDICAÇÃO DE LIVRO Clean Architecture (Robert C. Martin)

  168. Estudar arquitetura de so ware vai te mostrar que mágicas

    não existem!
  169. OBRIGADO! http://twitter.com/junior_grossi http://speakerdeck.com/jgrossi