devtalk zoox 04/2016

Post on 22-Jan-2018

124 Views

Category:

Software

1 Downloads

Preview:

Click to see full reader

TRANSCRIPT

ZOOX DEV TALK 04/2016

Princípios para melhorar um código

MOTIVAÇÃO

Por que devemos sempre melhorar o código?

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

AVISO

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

STUPID

Singleton

Tight Coupling

Untestability

Premature Optimization

Indescriptive Naming

Duplication

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

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

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

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)

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

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!

SOLID

Single Responsibility Principle

Open/Close Principle

Liskov Substitution Principle

Interface Segregation Principle

Dependency Inversion Principle

SINGLE RESPONSIBILITY PRINCIPLE

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

Divida classes grandes

Use camadas

Evite classes God

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?

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

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)

OCP - EXEMPLO

<?php

class Retangulo

{

public $altura;

public $largura;

}

class Area

{

public function calculaArea(Retangulo $retangulo)

{

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

}

}

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;

}

}

}

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

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

}

}

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

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

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

}

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

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;

}

}

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;

}

}

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;

}

}

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

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

}

}

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

}

}

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

}

}

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

}

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

top related