devtalk zoox 04/2016

32
ZOOX DEV TALK 04/2016 Princípios para melhorar um código

Upload: leandro-silva

Post on 22-Jan-2018

124 views

Category:

Software


1 download

TRANSCRIPT

Page 1: DevTalk Zoox 04/2016

ZOOX DEV TALK 04/2016

Princípios para melhorar um código

Page 2: DevTalk Zoox 04/2016

MOTIVAÇÃO

Por que devemos sempre melhorar o código?

Por que um código que funciona não é suficiente?

Page 3: DevTalk Zoox 04/2016

AVISO

Estes princípios são sugestões e não regras!

Page 4: DevTalk Zoox 04/2016

STUPID

Singleton

Tight Coupling

Untestability

Premature Optimization

Indescriptive Naming

Duplication

Page 5: DevTalk Zoox 04/2016

SINGLETON

Representa um estado global do seu código

Programas que usam estado global são difíceis de testar e debugar

Programas que dependem do estado global mascaram suas dependências

Page 6: DevTalk Zoox 04/2016

TIGHT COUPLING

Generalização do problema com Singleton

Se mudar um módulo te obriga a mudar outro módulo

Torna o código difícil de reusar e testar

Para evitar, favorecer composição sobre herança e usar injeção dedependência sempre que possível

Page 7: DevTalk Zoox 04/2016

UNTESTABILITY

Testes não devem ser difíceis

Deixar de escrever um teste economiza tempo de imediato, mas perdemuito mais depois ”caçando” bugs e testando manualmente (falho)

Se escrever um teste é difícil, o problema está no código

Normalmente, untestability é causada por tight coupling

Page 8: DevTalk Zoox 04/2016

PREMATURE OPTIMIZATION

Não super complique o código para otimizá-lo

Terá apenas custo e não benefício

Meça a performance antes de otimizar (benchmarks)

YAGNI = You Ain’t Gonna Need It (Você não vai precisar disso)

Page 9: DevTalk Zoox 04/2016

INDESCRIPTIVE NAMING

Nomeie classes, métodos, atributos apropriadamente

Não abrevie

Se não consegue achar um nome apropriado para uma classe, talvez a responsabilidade dela não esteja bem definida.

Linguagem de programação é para humanos

Para o computador, $vlna é o mesmo que $valorLitraoNoAlto

Page 10: DevTalk Zoox 04/2016

DUPLICAÇÃO

Se duplicar código e tiver que fazer um ajuste, terá que mexer emvários lugares (e se esquecer de um?)

DRY = Don’t Repeat Youself

KISS = Keep It Simple, Stupid!

Page 11: DevTalk Zoox 04/2016

SOLID

Single Responsibility Principle

Open/Close Principle

Liskov Substitution Principle

Interface Segregation Principle

Dependency Inversion Principle

Page 12: DevTalk Zoox 04/2016

SINGLE RESPONSIBILITY PRINCIPLE

Nunca deve haver mais de uma razão para uma classe mudar

Divida classes grandes

Use camadas

Evite classes God

Page 13: DevTalk Zoox 04/2016

SRP - EXEMPLO

<?php

class Livro

{

function getAutor()

{

return 'João da Silva';

}

function getTitulo()

{

return 'Grande Livro';

}

function virarPagina()

{

// Avança ponteiro de página

}

function mostraPaginaAtual()

{

echo 'Conteúdo da página';

}

}

O que há de errado no código?

Page 14: DevTalk Zoox 04/2016

SRP – EXEMPLO MELHORADO

<?php

class Livro

{

function getTitulo()

{

return 'Grande Livro';

}

function getPaginaAtual()

{

echo 'Conteúdo da página';

}

}

interface Printer

{

function printPage($page);

}

class PlainTextPrinter implements Printer

{

function printPage($page) {

echo $page;

}

}

class HtmlPrinter implements Printer

{

function printPage($page) {

echo '<div style="single-page">' . $page . '</div>';

}

}

$livro = new Livro();

$printer = new HtmlPrinter();

$printer->printPage($livro->getPaginaAtual());

Page 15: DevTalk Zoox 04/2016

OPEN/CLOSE PRINCIPLE

Classes devem ser abertas para expansão, mas fechadas para alteração

Defina todos os atributos como private

Sem variáveis globais

Evite setter (sempre que possível)

Page 16: DevTalk Zoox 04/2016

OCP - EXEMPLO

<?php

class Retangulo

{

public $altura;

public $largura;

}

class Area

{

public function calculaArea(Retangulo $retangulo)

{

return $retangulo->altura * $retangulo->largura;

}

}

Page 17: DevTalk Zoox 04/2016

OCP – EXEMPLO DE VIOLAÇÃO

<?php

class Retangulo

{

public $altura;

public $largura;

}

class Circulo

{

public $radio;

}

class Area

{

public function calculaArea($objeto)

{

if ($objeto instanceof Retangulo) {

return $objeto->altura * $objeto->largura;

} elseif ($objeto instanceof Circulo) {

return $objeto->circulo * $objeto->circulo * PI;

}

}

}

Page 18: DevTalk Zoox 04/2016

OCP – EXEMPLO DE VIOLAÇÃO

<?php

class Retangulo

{

public $altura;

public $largura;

}

class Circulo

{

public $radio;

}

class Area

{

public function calculaArea($objeto)

{

if ($objeto instanceof Retangulo) {

return $objeto->altura * $objeto->largura;

} elseif ($objeto instanceof Circulo) {

return $objeto->circulo * $objeto->circulo * PI;

}

}

}

Tivemos que alterar a classe Area para poder extendê-la. Ela não é

fechada para modificações = não éaberta para expansão

Page 19: DevTalk Zoox 04/2016

OCP – EXEMPLO MELHORADO

<?php

abstract class Forma

{

abstract function calculaArea();

}

class Retangulo extends Forma

{

public $altura;

public $largura;

public function calculaArea()

{

return $this->altura * $this->largura;

}

}

class Circulo extends Forma

{

public $radio;

public function calculaArea()

{

return $this->circulo * $this->circulo * PI;

}

}

class Area

{

public function calculaArea(Forma $objeto)

{

return $objeto->calculaArea();

}

}

Page 20: DevTalk Zoox 04/2016

LISKOV SUBSTITUTION PRINCIPLE

Subclasses devem poder ser substituidas por sua classe base

Classes filhas não devem quebrar as definições de suas bases

Objetos num código devem poder ser substituídos por seus subtipossem alterar o funcionamento correto do programa

Page 21: DevTalk Zoox 04/2016

LSP - EXEMPLO

<?php

class Retangulo

{

protected $altura;

protected $largura;

public function setLargura($largura)

{ $this->largura = $largura; }

public function setAltura($altura)

{ $this->altura = $altura; }

public function getArea()

{

return $this->altura * $this->largura;

}

}

$retangulo = new Retangulo();

$retangulo->setAltura(10);

$retangulo->setLargura(20);

if ($retangulo->getArea() !== 200) {

throw new \Exception('Área errada');

}

0

Page 22: DevTalk Zoox 04/2016

LSP - EXEMPLO DE VIOLAÇÃO

<?php

class Retangulo

{

protected $altura;

protected $largura;

public function setLargura($largura) { $this->largura = $largura; }

public function setAltura($altura) { $this->altura = $altura; }

public function getArea()

{

return $this->altura * $this->largura;

}

}

class Quadrado extends Retangulo

{

public function setLargura($largura)

{ $this->largura = $this->altura = $largura; }

public function setAltura($altura)

{ $this->altura = $this->largura = $altura; }

}

$quadrado = new Quadrado();

$quadrado->setAltura(10);

$quadrado->setLargura(20);

if ($quadrado->getArea() !== 200) {

throw new \Exception('Área errada');

}

Page 23: DevTalk Zoox 04/2016

INTERFACE SEGREGATION PRINCIPLE

Melhor ter várias interfaces específicas a uma só genérica

Uma classe não deveria implementar métodos que não usa

Usando ISP você garante low coupling e high coersion

Page 24: DevTalk Zoox 04/2016

ISP - EXEMPLO

<?php

interface Veiculo

{

public function liga();

public function abreMala();

public function numEixos();

public function ehMensalista();

}

class Carro implements Veiculo

{

}

class Estacionamento

{

public function permiteEntrada(Veiculo $veiculo)

{

return $veiculo->ehMensalista();

}

}

class Pedagio

{

public function custo(Veiculo $veiculo)

{

return $veiculo->numEixos() * 5;

}

}

Page 25: DevTalk Zoox 04/2016

ISP – EXEMPLO DE VIOLAÇÃO

<?php

interface Veiculo

{

public function liga();

public function abreMala();

public function numEixos();

public function ehMensalista();

}

class Carro implements Veiculo {}

class Moto implements Veiculo {}

class Estacionamento

{

public function permiteEntrada(Veiculo $veiculo)

{

return $veiculo->ehMensalista();

}

}

class Pedagio

{

public function custo(Veiculo $veiculo)

{

return $veiculo->numEixos() * 5;

}

}

Page 26: DevTalk Zoox 04/2016

ISP – EXEMPLO MELHORADO

<?php

interface Veiculo

{

public function liga();

}

interface Mensalista

{

public function ehMensalista();

}

interface Mala

{

public function abreMala();

}

interface Eixos

{

public function numEixos();

}

class Carro implements Veiculo, Mensalista, Mala, Eixos {}

class Moto implements Veiculo, Mensalista, Eixos {}

class Estacionamento

{

public function permiteEntrada(Mensalista $veiculo)

{

return $veiculo->ehMensalista();

}

}

class Pedagio

{

public function custo(Eixos $veiculo)

{

return $veiculo->numEixos() * 5;

}

}

Page 27: DevTalk Zoox 04/2016

DEPENDENCY INVERSION PRINCIPLE

Módulos de alto nível não devem depender de baixo nível, ambos devem depender de abstrações

Abstrações não devem depender de detalhes. Detalhes devemdepender de abstrações

Use o mesmo nível de abstração num determinado nível

Page 28: DevTalk Zoox 04/2016

DIP - EXEMPLO

<?php

class PDFReader {

private $book;

function __construct(PDFBook $book) {

$this->book = $book;

}

function read() {

return $this->book->read();

}

}

class PDFBook {

function read() {

return "lendo um livro pdf.";

}

}

class Test extends PHPUnit_Framework_TestCase {

function testItCanReadAPDFBook() {

$b = new PDFBook();

$r = new PDFReader($b);

$this->assertRegExp('/livro pdf/', $r->read());

}

}

Page 29: DevTalk Zoox 04/2016

DIP – EXEMPLO DE VIOLAÇÃO

<?php

class EBookReader {

private $book;

function __construct(PDFBook $book) {

$this->book = $book;

}

function read() {

return $this->book->read();

}

}

class PDFBook {

function read() {

return “lendo um livro pdf.";

}

}

class Test extends PHPUnit_Framework_TestCase {

function testItCanReadAPDFBook() {

$b = new PDFBook();

$r = new EBookReader($b);

$this->assertRegExp('/livro pdf/', $r->read());

}

}

Page 30: DevTalk Zoox 04/2016

DIP – EXEMPLO MELHORADO

<?php

interface EBook {

function read();

}

class EBookReader {

private $book;

function __construct(EBook $book) {

$this->book = $book;

}

function read() {

return $this->book->read();

}

}

class PDFBook implements Ebook {

function read() {

return " lendo um livro pdf.";

}

}

class Test extends PHPUnit_Framework_TestCase {

function testItCanReadAPDFBook() {

$b = new PDFBook();

$r = new EBookReader($b);

$this->assertRegExp('/livro pdf/', $r->read());

}

}

Page 31: DevTalk Zoox 04/2016

DIP – EXEMPLO MELHORADO 2

<?phpinterface EBook {

function read();}

class EBookReader {

private $book;

function __construct(EBook $book) {$this->book = $book;

}

function read() {return $this->book->read();

}

}

class PDFBook implements EBook {

function read() {return “lendo um livro pdf.";

}}

class MobiBook implements EBook {

function read() {return “lendo um livro mobi.";

}}

class Test extends PHPUnit_Framework_TestCase {

function testItCanReadAPDFBook() {$b = new PDFBook();$r = new EBookReader($b);

$this->assertRegExp('/livro pdf/', $r->read());}

function testItCanReadAMobiBook() {$b = new MobiBook();$r = new EBookReader($b);

$this->assertRegExp('/livro mobi/', $r->read());}

}

Page 32: DevTalk Zoox 04/2016

DIP – EXEMPLO MELHORADO 2

<?phpinterface EBook {

function read();}

class EBookReader {

private $book;

function __construct(EBook $book) {$this->book = $book;

}

function read() {return $this->book->read();

}

}

class PDFBook implements EBook {

function read() {return “lendo um livro pdf.";

}}

class MobiBook implements EBook {

function read() {return “lendo um livro mobi.";

}}

class Test extends PHPUnit_Framework_TestCase {

function testItCanReadAPDFBook() {$b = new PDFBook();$r = new EBookReader($b);

$this->assertRegExp('/livro pdf/', $r->read());}

function testItCanReadAMobiBook() {$b = new MobiBook();$r = new EBookReader($b);

$this->assertRegExp('/livro mobi/', $r->read());}

}

• Não precisamos mudar a classe EBooReader = OCP• Separamos as responsabilidades = SRP• Segregamos nossas interfaces = ISP• Usamos corretamente o subtipo = LSP

• DIP nos ajuda a manter os outros 4 princípios