Slide 1

Slide 1 text

BOAS PRÁTICAS COM PHP novidades, clean code e um pouco de arquitetura

Slide 2

Slide 2 text

Sou Junior Grossi twitter.com/junior_grossi github.com/jgrossi

Slide 3

Slide 3 text

Paciência!

Slide 4

Slide 4 text

https://github.com/corcel/corcel

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

https://glofox.com/careers

Slide 9

Slide 9 text

◽ 2004 php ◽ 2016 ◽

Slide 10

Slide 10 text

PARTE 1 PHP ANTES E DEPOIS Os últimos 10 anos da linguagem mais usada na Web!

Slide 11

Slide 11 text

PHP ARCHITECT Nov/2018 | Volume 17 | Issue 11

Slide 12

Slide 12 text

PHP EM 2019 Linguagem mais usada na Web (~80%) Só o WordPress é responsável por ~36% Muito problema pra resolver (mais empregos)

Slide 13

Slide 13 text

No content

Slide 14

Slide 14 text

PHP 5.3 (2009) O DIVISOR DE ÁGUAS NAMESPACES + LAMBDA FUNCTIONS/CLOSURES (Mudanças no processo interno de releases do PHP)

Slide 15

Slide 15 text

REQUEST FOR COMMENTS (RFC) https://wiki.php.net/rfc

Slide 16

Slide 16 text

NAMESPACES Classes não podiam ter o mesmo nome HtmlPrinter, Zend_HtmlPrinter class Zend_HtmlPrinter { public function print(); }

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

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);

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

2012 PHP 5.4 + COMPOSER ANO DAS MAIORES MUDANÇAS (Mudou de vez a comunidade PHP)

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

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];

Slide 23

Slide 23 text

BUILT-IN WEB SERVER Não é necessário mais um Web server pra desenvolvimento > php ­S localhost:8000

Slide 24

Slide 24 text

COMPOSER Package Manager oficial do PHP http://getcomposer.org

Slide 25

Slide 25 text

COMPOSER Resolveu o problema do Ctr C + Ctr V + controle de versões

Slide 26

Slide 26 text

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');

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

AUTOLOADING + NAMESPACES use Corcel\Model\Post;

Slide 29

Slide 29 text

PACKAGIST http://packagist.org

Slide 30

Slide 30 text

PHP-FIG PSR (PHP STANDARD RECOMMENDATION) code style, autoload, interfaces padronizaram a toda

Slide 31

Slide 31 text

https://www.php-fig.org

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

PHP 7 TUDO NOVO, DE NOVO!

Slide 35

Slide 35 text

PERAÍ, E O PHP 6?

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

PHP 7 (2015) Nova Zend Engine (v3) 2x mais rápido que PHP 5 50% menos de consumo de memória

Slide 38

Slide 38 text

No content

Slide 39

Slide 39 text

No content

Slide 40

Slide 40 text

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];

Slide 41

Slide 41 text

PHP 7.0 NULL COALESCE OPERATOR: ?? // Before $age = isset($data['age']) ? $data['age'] : 100; // After $age = $data['age'] ?? 100;

Slide 42

Slide 42 text

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 }

Slide 43

Slide 43 text

STRICT TYPES = 1 declare(strict_types=1); namespace Foo\Printer; class CsvPrinter implements PrinterInterface { public function __construct(string $foo, float $bar) { // ... } }

Slide 44

Slide 44 text

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 };

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

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 }

Slide 47

Slide 47 text

NOVIDADES: PHP 7.4 NOV/2019 Preloading* Short closures Typed properties Improved type variance The null coalescing assignment operator muito mais!

Slide 48

Slide 48 text

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)

Slide 49

Slide 49 text

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; }

Slide 50

Slide 50 text

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]; }

Slide 51

Slide 51 text

PHP 8 ❤ JIT (just in time) compiler (vídeo do Zeev)

Slide 52

Slide 52 text

No content

Slide 53

Slide 53 text

CONSIDERAÇÕES FINAIS PHP é uma das linguagens mais maduras Excelente performance (e vai melhorar!) Desenvolvimento muito rápido!

Slide 54

Slide 54 text

PHP DO JEITO CERTO http://br.phptherightway.com/

Slide 55

Slide 55 text

PARTE 2 CLEAN CODE resumão pra quem comprou mas não leu o livro!

Slide 56

Slide 56 text

LIVRO Clean Code A Handbook of Agile So ware Cra smanship Robert C. Martin (Uncle Bob)

Slide 57

Slide 57 text

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

Slide 58

Slide 58 text

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

Slide 59

Slide 59 text

(bootstrap time!)

Slide 60

Slide 60 text

"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

Slide 61

Slide 61 text

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!

Slide 62

Slide 62 text

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

Slide 63

Slide 63 text

EXPRESSE INTENÇÃO AO DAR NOMES Use nomes pronunciáveis / Evite abreviações

Slide 64

Slide 64 text

class DtaRcrd102 { private DateTime $genymdhsm; private DateTime $modymdhms; private string $pszqint = "102"; } class Customer { private DateTime $generationTimestamp; private DateTime $modificarionTimestamp; private string $recordId = "102"; }

Slide 65

Slide 65 text

NOMES "BUSCÁVEIS" / CONSTANTES for ($i = 0; $i < 5; $i++) { // ... } for ($i = 0; $i < WORK_DAYS_PER_WEEK; $i++) { // ... }

Slide 66

Slide 66 text

EVITE PREFIXOS/SUFIXOS DESNECESSÁRIOS $txtFirstName = $controller­>request()­>get('txt_FirstName');

Slide 67

Slide 67 text

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

Slide 68

Slide 68 text

EVITE O "MAPA MENTAL" Não obrigue o usuário a tentar entender o que está escrito Buscar entender pelo contexto é muito mais demorado!

Slide 69

Slide 69 text

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)

Slide 70

Slide 70 text

NOMES DE MÉTODOS Devem ser verbos Devem ser declarativos (ações) Accessors (get), Mutators (set) e predicates (is)

Slide 71

Slide 71 text

UMA PALAVRA POR CONCEITO Nunca misture palavras de conceitos similares fetch, retrieve, get

Slide 72

Slide 72 text

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

Slide 73

Slide 73 text

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

Slide 74

Slide 74 text

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

Slide 75

Slide 75 text

FUNÇÕES/MÉTODOS PEQUENOS Máximo 20 linhas. Se possível menos. Máximo 120 caracteres por linha. Se possível 80.

Slide 76

Slide 76 text

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

Slide 77

Slide 77 text

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

Slide 78

Slide 78 text

"STEPDOWN RULE" Leitura fluente como texto if (!$user = $this­>findUser()) { // ... } $this­>save($user); $user = $this­>findUser(); if (!$user) { // ... } $this­>save($user);

Slide 79

Slide 79 text

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; }

Slide 80

Slide 80 text

switch Tolerados se aparecerem apenas uma vez Pensar em AbstractFactory se mais de uma vez Cuidado para não ferir SRP

Slide 81

Slide 81 text

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

Slide 82

Slide 82 text

ARGUMENTOS Nenhum é sempre melhor 1 ou 2 aceitáveis / 3 deve ser evitado (aumento do número de argumentos dificulta escrever testes)

Slide 83

Slide 83 text

"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!)

Slide 84

Slide 84 text

private function doSomething(string $foo, bool $bar): void { if ($bar) { // something } // ... }

Slide 85

Slide 85 text

Encapsule argumentos em objetos (dá mais significado ao argumento) private function makeCircle(float $x, float $y): Circle { // ... } private function makeCircle(Point $point): Circle { // ... }

Slide 86

Slide 86 text

Verbos e palavras-chave (dá mais significado ao argumento) public function find(Email $email): User { // ... } public function findUserByEmail(Email $email): User { // ... }

Slide 87

Slide 87 text

CAPÍTULO 4 Comentários "Don't comment bad code - rewrite it." Brian W. Kernighan e P. J. Plaugher

Slide 88

Slide 88 text

"Truth can only be found in one place: the code. Only the code can truly tell you what it does."

Slide 89

Slide 89 text

No content

Slide 90

Slide 90 text

CONSIDERAÇÕES Remova comentários que não adicionam nada (docblock) Referências internas Críticas ou sugestões

Slide 91

Slide 91 text

/** * Returns the day of the month. * * @return int the day of the month. */ public function getDayOfMonth(): int { return $this­>dayOfMonth; }

Slide 92

Slide 92 text

No content

Slide 93

Slide 93 text

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

Slide 94

Slide 94 text

CAPÍTULO 5 Formatação Visual importa sim!

Slide 95

Slide 95 text

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

Slide 96

Slide 96 text

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; }

Slide 97

Slide 97 text

Indentação. Nem precisa falar, né?

Slide 98

Slide 98 text

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

Slide 99

Slide 99 text

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

Slide 100

Slide 100 text

LEI DE DEMETER "Fale com amigos, não com estranhos." Encapsule o máximo possível. Exponha apenas o necessário.

Slide 101

Slide 101 text

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

Slide 102

Slide 102 text

Exceptions sempre. Código de erro nunca! Escreva o bloco try/catch primeiro (facilita pensar em todas as possíveis exceções)

Slide 103

Slide 103 text

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; }

Slide 104

Slide 104 text

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

Slide 105

Slide 105 text

NULL RETURN Evite retornar null Dispare exception e trate na origem Use Null Objects

Slide 106

Slide 106 text

NÃO PASSE NULL COMO PARÂMETRO Perde consistência Adiciona complexidade (mais ifs)

Slide 107

Slide 107 text

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

Slide 108

Slide 108 text

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.

Slide 109

Slide 109 text

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

Slide 110

Slide 110 text

DICAS PARA CLEAN TESTS Apenas um conceito por teste (cada caso possível é um novo teste)

Slide 111

Slide 111 text

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

Slide 112

Slide 112 text

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

Slide 113

Slide 113 text

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

Slide 114

Slide 114 text

CAPÍTULO 10 Classes "Let's talk about Clean Classes"

Slide 115

Slide 115 text

ENCAPSULAMENTO private por padrão protected quando necessário (herança ou testes) Foco sempre em encapsular primeiro! (use abstrações)

Slide 116

Slide 116 text

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)

Slide 117

Slide 117 text

"COMPOSITION OVER INHERITANCE" Mais fácil com classes menores Nova funcionalidade? Nova classe + Dependency Injection da anterior!

Slide 118

Slide 118 text

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; } }

Slide 119

Slide 119 text

CONCLUSÕES Qualidade é um execício diário Comece a praticar (experiência) Melhoria de processos Diminuição de complexidade

Slide 120

Slide 120 text

PARTE 3 CLEAN ARCHITECTURE um pouco de arquitetura não faz mal a ninguém!

Slide 121

Slide 121 text

ARQUITETURA & DESIGN

Slide 122

Slide 122 text

ARQUITETURA Visão em alto nível "Arquitetura de uma casa" Conexões e Comunicação de modo geral

Slide 123

Slide 123 text

DESIGN Estruturas e decisões em baixo nível "Estilo dos móveis de uma casa" Design Patterns

Slide 124

Slide 124 text

Robert C. Martin "O objetivo da arquitetura de so ware é minimizar os recursos humanos necessários para construir e manter um sistema."

Slide 125

Slide 125 text

DESENVOLVIMENTO So ware difícil de manter tem vida curta Arquitetura facilita desenvolvimento para o time que o mantém

Slide 126

Slide 126 text

Uma boa arquitetura começa com bons acordos Decisões em conjunto (time!) Comunicação é fundamental Mudar arquitetura é muito caro!

Slide 127

Slide 127 text

MATURIDADE Às vezes grandes projetos começam pequenos Zero (ou pouca) arquitetura Problemas de arquitetura aparecem bem depois

Slide 128

Slide 128 text

OBJETIVOS Fácil desenvolvimento / baixo custo Publicação rápida e fácil Diminuir custos com manutenção (custo mais caro)

Slide 129

Slide 129 text

ARQUITETURA EM CAMADAS "Deixe opções em aberto" Camadas independentes Casos de uso independentes Comandos independentes

Slide 130

Slide 130 text

SCREAMING ARCHITECTURE

Slide 131

Slide 131 text

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

Slide 132

Slide 132 text

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

Slide 133

Slide 133 text

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

Slide 134

Slide 134 text

A Web é uma arquitetura?

Slide 135

Slide 135 text

Não! Web é o mecanismo de entrega Sua arquitetura não deve se preocupar com entrega A Web é apenas um detalhe

Slide 136

Slide 136 text

SOBRE TESTES

Slide 137

Slide 137 text

Mais fácil escrever (e manter) "unit tests" em arquitetura totalmente baseada em casos de uso.

Slide 138

Slide 138 text

PARA TESTAR: Você não precisa de framework Você não precisa de servidor web Você não precisa de banco de dados

Slide 139

Slide 139 text

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

Slide 140

Slide 140 text

"Sua arquitetura deve dizer aos leitores sobre o sistema, não sobre o framework usado no sistema."

Slide 141

Slide 141 text

CLEAN ARCHITECTURE

Slide 142

Slide 142 text

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

Slide 143

Slide 143 text

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

Slide 144

Slide 144 text

HEXAGONAL ARCHITECTURE "Hexagonal Architecture - Message-Oriented So ware Design" (Matthias Noback) https://youtu.be/K1EJBmwg9EQ

Slide 145

Slide 145 text

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

Slide 146

Slide 146 text

"INDEPENDÊNCIA"

Slide 147

Slide 147 text

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

Slide 148

Slide 148 text

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.

Slide 149

Slide 149 text

THE DEPENDENCY RULE (AS 4 CAMADAS) 1. Entities (Enterprise Business Rules) 2. Use Cases (Application Business Rules) 3. Interface Adapters 4. Frameworks and Drivers

Slide 150

Slide 150 text

1. ENTITIES Encapsulamento de "Regras de Negócio" críticas Conjunto de classes e métodos

Slide 151

Slide 151 text

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)

Slide 152

Slide 152 text

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.

Slide 153

Slide 153 text

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

Slide 154

Slide 154 text

ATRAVESSANDO LIMITES ⬆ Usando Dependency Inversion (SOLID) Exemplo: caso real - microserviço "tax"

Slide 155

Slide 155 text

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)

Slide 156

Slide 156 text

POR ONDE COMEÇAR? Command/Handler Pattern Command seria um "DTO" Handler seria o "Use Case"

Slide 157

Slide 157 text

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.

Slide 158

Slide 158 text

(1) Command para (1) Handler

Slide 159

Slide 159 text

USE CASE: CREATE USER CreateUserCommand / CreateUserHandler

Slide 160

Slide 160 text

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

Slide 161

Slide 161 text

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

Slide 162

Slide 162 text

2. COMMAND Classe simples que guarda os dados necessários para execução da ação. Classe imutável!

Slide 163

Slide 163 text

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

Slide 164

Slide 164 text

3. HANDLER Caso de uso propriamente dito Recebe o Command com todos os dados necessários

Slide 165

Slide 165 text

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 ]); } }

Slide 166

Slide 166 text

PRÓXIMO PASSO Adicionar um CommandBus (responsável por executar os Handlers) composer require league/tactician composer require illuminate/bus

Slide 167

Slide 167 text

INDICAÇÃO DE LIVRO Clean Architecture (Robert C. Martin)

Slide 168

Slide 168 text

Estudar arquitetura de so ware vai te mostrar que mágicas não existem!

Slide 169

Slide 169 text

OBRIGADO! http://twitter.com/junior_grossi http://speakerdeck.com/jgrossi