SlideShare uma empresa Scribd logo
1 de 81
Baixar para ler offline
CÓDIGO LEGADO 
Michael Granados / @dgmike
MICHAEL GRANADOS 
Conversor de sonhos de grandes investidores em realidade
AGENDA 
WTF? 
A vítima 
Versionamento 
Pacotes, pacotes, pacotes... 
Um grupo, um código 
Testes 
Programação Calistênica
A VÍTIMA 
http://github.com/dgmike/phpconference2014-vitima
WTF?
WTF? 
Código sujo
WTF? 
Código ruim
WTF? 
Código feio
WTF? 
Código mal-feito
WTF? 
Código não orientado a objetos
WTF? 
Código rebuscado
WTF? 
Código espaguete
CÓDIGO LEGADO! 
To me, legacy code is simply code without tests. 
Michael Feathers
VERSIONAMENTO
COMECE AGORA! 
csv 
subversion (svn) 
mercurial (hg) 
git
PARE DE TRABALHAR NO SERVIDOR! 
Tenha uma cópia do projeto em sua máquina 
$ cd projeto_que_fiz_download 
$ git init 
$ git add . 
$ git commit -m "Importando projeto para o git"
AHH.... MAS EU TENHO MEDO DESSA "TELA PRETA" 
Chega de desculpas: TortoiseGit
DIA-A-DIA
LOG DE ATIVIDADES 
$ git log --oneline -n 10 
0b66a73 Adding stepup uptater 
207d43f Updating phpdocumentor to get last corrections 
6015990 creating make file 
d54aafa some doc misc 
b2a8726 misc 
c8c3624 Documentor settings 
70697d4 Adding phpdocumentor to dev 
239f47d Merge pull request #16 from dgmike/enhancement/#14 
bf53652 "method" implementation 
f3653c8 "method" signature
O QUE MUDOU? 
$ git diff --name-only b2a8726..HEAD 
.stepuprc 
Makefile 
composer.json 
src/Apolo.php 
src/Route.php
FUNCIONA SOMENTE NA MINHA MÁQUINA? 
github 
gitlab 
bitbucket 
No seu servidor linux (git init --bare / gitosis) 
Na máquina do seu amigo (via ip de rede + ssh)
NOVO FLUXO DE TRABALHO
PACOTES, PACOTES, PACOTES... 
Iremos precisar de ferramentas que irão nos auxiliar ao longo de 
nossa jornada. 
Fazer download do zip e descompactar é tão anos 90... 
Utilize algum gerenciador de pacotes: pear, composer, npm, 
bower
UTILIZAREMOS COMPOSER 
Fácil de instalar 
$ curl -sS https://getcomposer.org/installer | php
UTILIZAREMOS COMPOSER 
Fácil de usar 
// composer.json 
{ 
"require": { 
"monolog/monolog": "1.2.*" 
} 
} 
$ php composer.phar install
UTILIZAREMOS COMPOSER 
Usar em sua aplicação 
require 'vendor/autoload.php';
UM GRUPO, UM CÓDIGO
UM GRUPO, UM CÓDIGO 
function dinheiro($valor) { 
return 'R$ ' . number_format( 
$valor, 2, '.', '' 
); 
} 
function precoComDesconto ($produtos, $codigo_promocional = false) 
{ 
$total = 0; 
foreach ( $produtos as $produto ) 
{ 
$total += $produto['preco_final']; 
} 
$porcentagem = 0; 
if ( count($produtos) == 2 ) {
UM GRUPO, UM CÓDIGO 
Tabs vs Espaços? 
2 ou 4 espaços? 
Final de linha? mac, linux, windows?
EDITORCONFIG.ORG
EDITORCONFIG.ORG 
# .editorconfig 
# top-most EditorConfig file 
root = true 
# Unix-style newlines with a newline ending every file 
[*] 
end_of_line = lf 
insert_final_newline = true 
# Matches multiple files with brace expansion notation 
# Set default charset 
[*.{js,py}] 
charset = utf-8 
# 4 space indentation 
[*.php] 
indent_style = space 
indent_size = 4
CODESNIFFER 
// composer.json 
{ 
"require-dev": { 
"squizlabs/php_codesniffer": "*" 
} 
} 
$ composer install
CODESNIFFER 
$ ./vendor/bin/phpcs --standard=PSR2 funcoes.php 
FILE: ./funcoes.php 
-------------------------------------------------------------------------------- 
FOUND 16 ERROR(S) AFFECTING 10 LINE(S) 
-------------------------------------------------------------------------------- 
7 | ERROR | Expected "foreach (...) {n"; found "foreach(...)n {n" 
7 | ERROR | Space found after opening bracket of FOREACH loop 
7 | ERROR | Space found before closing bracket of FOREACH loop 
7 | ERROR | Expected 0 spaces after opening bracket; 1 found 
7 | ERROR | Expected 0 spaces before closing bracket; 1 found 
30 | ERROR | Expected "if (...) {n"; found "if (...)n {n" 
34 | ERROR | Opening parenthesis of a multi-line function call must be the 
| | last content on the line 
36 | ERROR | Closing parenthesis of a multi-line function call must be on a 
| | line by itself 
47 | ERROR | Expected "function abc(...)"; found "function abc (...)" 
47 | ERROR | Expected 0 spaces between argument "$codigo_promocional" and 
| | closing bracket; 1 found 
47 | ERROR | Opening brace should be on a new line
CODESNIFFER 
function dinheiro($valor) { 
return 'R$ ' . number_format( 
$valor, 2, '.', '' 
); 
} 
function precoComDesconto ($produtos, $codigo_promocional = false) 
{ 
$total = 0; 
foreach ( $produtos as $produto ) 
{ 
$total += $produto['preco_final']; 
} 
$porcentagem = 0; 
if ( count($produtos) == 2 ) {
CODESNIFFER 
function dinheiro($valor) 
{ 
return 'R$ ' . number_format($valor, 2, '.', ''); 
} 
function precoComDesconto($produtos, $codigo_promocional = false) 
{ 
$total = 0; 
foreach ($produtos as $produto) { 
$total += $produto['preco_final']; 
} 
$porcentagem = 0; 
if (count($produtos) == 2) { 
$porcentagem = 5; 
$total = $total - ($total * 5/100);
TESTES 
function calculaJuros($produtos, $juros) 
{ 
echo '<pre>'; print_r($produtos); echo '</pre>'; // teste 
$total = 0; 
foreach($produtos as $produto) { 
$total += $produto['valor_real']; 
} 
$total = $total + ($total * $juros / 100); 
die($total); // teste 
return $total; 
}
TESTES 
Pacotes: PHPUnit, SimpleTest 
Tipos: unitários, integração, aceitacao
SIMPLETEST 
$ php composer.phar require --dev "lastcraft/simpletest:*"
SIMPLETEST 
define('SIMPLETEST_DIR', realpath(__DIR__ . '/../../vendor/lastcraft/simpletest')); 
require SIMPLETEST_DIR . '/autorun.php'; 
require SIMPLETEST_DIR . '/web_tester.php'; 
class TestIndex extends WebTestCase 
{ 
function testHomePage() 
{ 
$this->assertTrue($this->get('http://localhost:3001')); 
$this->assertText('Loja Legado'); 
} 
function testCliqueComprarAdicionaLinkCarrinhoDeCompras() 
{ 
$this->assertTrue($this->get('http://localhost:3001')); 
$this->assertNoText('Carrinho de compras');
SIMPLETEST 
$ php tests/aceitacao/test_index.php 
test_index.php 
OK 
Test cases run: 1/2, Passes: 13, Failures: 0, Exceptions: 0 
test_index.php 
1) Text [texto inexistente] not detected in [String: Loja Legado Loja Legado Loja Legado Carrinho de compras in testCliqueComprarAdicionaLinkCarrinhoDeCompras 
in TestIndex 
FAILURES!!! 
Test cases run: 1/2, Passes: 12, Failures: 1, Exceptions: 0
PHPUNIT 
$ php composer.phar require --dev 'phpunit/phpunit:*'
PHPUNIT 
require_once __DIR__ . '/../../funcoes.php'; 
class FuncoesTest 
extends PHPUnit_Framework_TestCase 
{ 
public function testDinheiro() 
{ 
$dinheiro = dinheiro(24); 
$this->assertEquals('R$ 24,00', $dinheiro); 
} 
}
PHPUNIT 
$ ./vendor/bin/phpunit tests/unitarios/funcoes_test.php 
PHPUnit 4.3.5 by Sebastian Bergmann. 
.. 
Time: 33 ms, Memory: 3.00Mb 
OK (2 tests, 4 assertions)
PHPUNIT 
$ ./vendor/bin/phpunit --testdox tests/unitarios/funcoes_test.php 
PHPUnit 4.3.5 by Sebastian Bergmann. 
Funcoes 
[x] Dinheiro 
[x] Preco com desconto 
$ ./vendor/bin/phpunit --tap tests/unitarios/funcoes_test.php 
TAP version 13 
ok 1 - FuncoesTest::testDinheiro 
ok 2 - FuncoesTest::testPrecoComDesconto 
1..2
PHPUNIT 
O que dá pra fazer? 
Mock/Stub 
Pre-popular banco de dados 
CodeCoverage 
Selenium
PROGRAMAÇÃO CALISTÊNICA
PROGRAMAÇÃO CALISTÊNICA 
é uma forma de atividade que consiste em uma 
Calistenia 
variedade de exercícios físicos feitos sem equipamentos ou 
pesos que têm por objetivo aumentar a força e a flexibilidade 
usando o peso do próprio corpo como resistência 
Jeff Bay escreveu um artigo no livro "The ThoughtWorks 
Antology" entitulado "Object Calisthenics". Ele propõe um 
exercício "calistênico" para melhorar o design de software e 
ajudar a internalizar princípios de bom design de programação 
orientada a objetos
ALGUNS PONTOS RELEVANTES! 
PHP não é JAVA!!! 
Algumas alterações serão feitas! 
São apenas dicas e não regras!
REGRAS DO EXERCÍCIO 
1. Use apenas um nível de identação por método 
2. Não use else 
3. Crie objetos para tipos primitivos e strings 
4. Use apenas um ponto por linha 
5. Não abrevie 
6. Mantenha todas as entidades pequenas 
7. Não use classes com mais de duas variáveis instanciadas 
8. Não use coleções de primeira-classe 
9. Não use Getters/Setters/Properties
USE APENAS UM NÍVEL DE IDENTAÇÃO POR MÉTODO 
function ganho($registros) 
{ 
$ganhosTotais = 0; 
foreach($registros as $registro) { 
foreach ($registro['produtos'] as $produto) { 
$ganhosTotais += $produto['valor_real'] - $produto['valor_compra']; 
} 
} 
return $ganhosTotais; 
}
USE APENAS UM NÍVEL DE IDENTAÇÃO POR MÉTODO 
function ganho($registros) 
{ 
$ganhosTotais = 0; 
foreach($registros as $registro) { 
$ganhosTotais += ganhosPorRegistro($registro); 
} 
return $ganhosTotais; 
} 
function ganhosPorRegistro($registro) 
{ 
$ganhos = 0; 
foreach ($registro['produtos'] as $produto) { 
$ganhos += $produto['valor_real'] - $produto['valor_compra']; 
} 
return $ganhos; 
}
NUNCA USE ELSE 
function precoFinal($produto) 
{ 
if ($produto['desconto'] > 0) { 
$precoFinal = $produto['preco'] - ($produto['preco'] * $produto['desconto'] / 100); 
} else { 
$precoFinal = $produto['preco']; 
} 
return $precoFinal; 
}
NUNCA USE ELSE 
function precoFinal($produto) 
{ 
if ($produto['desconto'] > 0) { 
return $produto['preco'] - ($produto['preco'] * $produto['desconto'] / 100); 
} 
return $precoFinal = $produto['preco']; 
} 
Outro exemplo 
function precoFinal($produto) 
{ 
$precoFinal = $produto['preco']; 
if ($produto['desconto'] > 0) { 
$precoFinal = $produto['preco'] - ($produto['preco'] * $produto['desconto'] / 100); 
} 
return $precoFinal; 
}
CRIE OBJETOS PARA TIPOS PRIMITIVOS E STRINGS SE ELES 
POSSUIREM ALGUM COMPORTAMENTO
CRIE OBJETOS PARA TIPOS PRIMITIVOS E STRINGS SE ELES 
POSSUIREM ALGUM COMPORTAMENTO 
function desconto(array $produtos, $desconto) 
{ 
$total = 0; 
foreach($produtos as $produto) { 
$total += $produto['valor_real']; 
} 
return $total - ($total * $desconto / 100); 
}
CRIE OBJETOS PARA TIPOS PRIMITIVOS E STRINGS SE ELES 
POSSUIREM ALGUM COMPORTAMENTO 
class ProdutosLista { 
protected $produtos; 
public function __construct(array $produtos) { 
$this->produtos = $produtos; 
} 
public function valor_real_total() { 
$total = 0; 
foreach ($this->produtos as $produto) { 
$total += $produto['valor_real']; 
} 
return $total; 
} 
}
CRIE OBJETOS PARA TIPOS PRIMITIVOS E STRINGS SE ELES 
POSSUIREM ALGUM COMPORTAMENTO 
class Numeral { 
protected $valor; 
public function __construct($valorInicial = 0) { 
$this->valor = $valorInicial; 
} 
public function valor() { 
return $this->valor; 
} 
public function adiciona(Numeral $valor) { 
$this->valor += $valor->valor(); 
} 
public function removerPercentual(Numeral $percentual) { 
$this->valor -= $this->valor() * $percentual / 100; 
} 
}
CRIE OBJETOS PARA TIPOS PRIMITIVOS E STRINGS SE ELES 
POSSUIREM ALGUM COMPORTAMENTO 
function desconto(ProdutosLista $produtos, Numeral $desconto) 
{ 
$total = new Numeral($produtos->valor_real_total()); 
$total->removerPercentual($desconto); 
return $total; 
}
USE APENAS UM PONTO ( -> ) POR LINHA SE NÃO FOR UM 
ENCADEAMENTO OU UM GETTER
USE APENAS UM ( -> ) POR LINHA SE NÃO FOR UM 
ENCADEAMENTO OU UM GETTER 
function categoria(ProdutoLista $produtos) 
{ 
return $produtos->primeiro->categoria->nome->humanizado(); 
}
USE APENAS UM ( -> ) POR LINHA SE NÃO FOR UM 
ENCADEAMENTO OU UM GETTER 
function categoria(ProdutoLista $produtos) 
{ 
$categoria = $produtos->primeiraCategoria(); 
$template = $categoria->decorator(new HumanizadoDecorator); 
return $template->renderiza(); 
}
USE APENAS UM ( -> ) POR LINHA SE NÃO FOR UM 
ENCADEAMENTO OU UM GETTER 
$this possui um valor especial no PHP 
class Produtos 
{ 
protected $produtos; 
public function primeiraCategoria() 
{ 
// em java: primeiroProduto.categoria() 
return $this->primeiroProduto->categoria(); 
} 
}
USE APENAS UM ( -> ) POR LINHA SE NÃO FOR UM 
ENCADEAMENTO OU UM GETTER 
$this possui um valor especial no PHP 
$filtros->adicionaImagem($imagem) 
->adicionarFiltro(new PretoBranco) 
->adicionarFiltro(new BordaMadeira);
NÃO ABREVIE
ESTÁ ESCREVENDO A MESMA VARIÁVEL MUITAS VEZES? 
Parece que temos um código reutilizado várias vezes. 
Talvez tenhamos duplicação de código
O NOME DO MÉTODO ESTÁ MUITO GRANDE? 
Talvez sua classe/metodo está executando mais do que deveria. 
Talvez tenhamos um problema de responsabilidade
MANTENHA TODAS AS ENTIDADES PEQUENAS 
Nada de classes com mais de 50 linhas 
Nada de pacotes/diretórios com mais de 10 arquivos
MANTENHA TODAS AS ENTIDADES PEQUENAS 
Nada de classes com mais de 100 linhas 
Nada de pacotes/diretórios com mais de 15 arquivos
NÃO USE CLASSES COM MAIS DE DUAS VARIÁVEIS 
INSTANCIADAS
TÁ... EU SEI...
NÃO USE CLASSES COM MAIS DE CINCO VARIÁVEIS 
INSTANCIADAS
USE COLEÇÕES COMO PRIMEIRA-CLASSE 
class Usuario 
{ 
protected $fotos = array(); 
protected $nome = ''; 
public function nome() { return $this->nome; } 
public function linkFotos() { 
$links = array(); 
foreach($this->fotos as $foto) { 
$links[] = $foto['link']; 
} 
return implode("n", $links); 
} 
}
USE COLEÇÕES COMO PRIMEIRA-CLASSE 
class Usuario 
{ 
protected $fotos = null; 
protected $nome = ''; 
public function nome() { return $this->nome; } 
public function fotos() { return $this->fotos; } 
} 
ListaFotos { 
protected $fotos = array(); 
}
USE COLEÇÕES COMO PRIMEIRA-CLASSE 
$fotos->filtrar(...); 
$fotos->mapear(...); 
$fotos->adicionar(...); 
$fotos->original(...);
NÃO USE GETTERS/SETTERS 
class Pessoa 
{ 
protected $nome; 
public getNome() { return $this->nome; } 
public setNome($nome) { $this->nome = $nome; } 
}
USE GETTERS/SETTERS 
class Pessoa 
{ 
protected $nome; 
public getNome() { 
return $this->nome; 
} 
public maiusculizaNome() 
{ 
$this->nome = strtoupper($this->nome); 
} 
}
SURPRESA! 
DOCUMENTE SEU CÓDIGO 
// verifica se tem mais de 20 produtos 
if ($produtos->total() > 20) { 
$produtos->aplicaDesconto(new Desconto(10)); 
}
DOCUMENTE SEU CÓDIGO 
// resgata somente fotos ativas 
$fotos = array_map( 
$fotos->filter('ativos'), 
create_function('$foto', 'return $foto["link"];') 
); 
Não explique um código ruim, corrijá-o! 
$fotos->filter('ativos')->links();
PHPDOC 
/** 
* Verifica se as credenciais do usuário estão corretas 
* 
* @todo implementar conexao com banco de dados 
* @param String $email Email do usuario 
* @param String $senha Senha do usuario 
* 
* @return Boolean 
*/ 
function verificaLogin(String $email, String $senha) { 
// ... 
}
DÚVIDAS? 
Seu momento de me deixar sem graça! ;-)
OBRIGADO! 
@dgmike - http://www.slideshare.net/dgmike

Mais conteúdo relacionado

Mais procurados

JS Experience 2017 - Performance Web além do carregamento
JS Experience 2017 - Performance Web além do carregamentoJS Experience 2017 - Performance Web além do carregamento
JS Experience 2017 - Performance Web além do carregamentoiMasters
 
JS Experience 2017 - Web APIs que você provavelmente não sabia que existiam
JS Experience 2017 - Web APIs que você provavelmente não sabia que existiamJS Experience 2017 - Web APIs que você provavelmente não sabia que existiam
JS Experience 2017 - Web APIs que você provavelmente não sabia que existiamiMasters
 
Proxy, Man-In-The-Middle e testes
Proxy, Man-In-The-Middle e testesProxy, Man-In-The-Middle e testes
Proxy, Man-In-The-Middle e testesStanislaw Pusep
 
PHP Experience 2016 - [Palestra] Keynote: PHP-7
PHP Experience 2016 - [Palestra] Keynote: PHP-7PHP Experience 2016 - [Palestra] Keynote: PHP-7
PHP Experience 2016 - [Palestra] Keynote: PHP-7iMasters
 
Desenvolvimento ágil com Kohana framework
Desenvolvimento ágil com Kohana frameworkDesenvolvimento ágil com Kohana framework
Desenvolvimento ágil com Kohana frameworkMarcelo Rodrigo
 
Introdução à MEAN Stack
Introdução à MEAN StackIntrodução à MEAN Stack
Introdução à MEAN StackBruno Catão
 
Perl Moderno, dia3
Perl Moderno, dia3Perl Moderno, dia3
Perl Moderno, dia3garux
 
PHP para Adultos: Clean Code e Object Calisthenics
PHP para Adultos: Clean Code e Object CalisthenicsPHP para Adultos: Clean Code e Object Calisthenics
PHP para Adultos: Clean Code e Object CalisthenicsGuilherme Blanco
 
PHP Jedi - Boas Práticas e Alta Performance
PHP Jedi - Boas Práticas e Alta PerformancePHP Jedi - Boas Práticas e Alta Performance
PHP Jedi - Boas Práticas e Alta PerformanceFelipe Ribeiro
 
Java 8 - Afinal onde usamos no dia a dia? GOJava 15 anos!
Java 8 - Afinal onde usamos no dia a dia? GOJava 15 anos!Java 8 - Afinal onde usamos no dia a dia? GOJava 15 anos!
Java 8 - Afinal onde usamos no dia a dia? GOJava 15 anos!Frederico Maia Arantes
 

Mais procurados (20)

JS Experience 2017 - Performance Web além do carregamento
JS Experience 2017 - Performance Web além do carregamentoJS Experience 2017 - Performance Web além do carregamento
JS Experience 2017 - Performance Web além do carregamento
 
JS Experience 2017 - Web APIs que você provavelmente não sabia que existiam
JS Experience 2017 - Web APIs que você provavelmente não sabia que existiamJS Experience 2017 - Web APIs que você provavelmente não sabia que existiam
JS Experience 2017 - Web APIs que você provavelmente não sabia que existiam
 
Proxy, Man-In-The-Middle e testes
Proxy, Man-In-The-Middle e testesProxy, Man-In-The-Middle e testes
Proxy, Man-In-The-Middle e testes
 
PHP Experience 2016 - [Palestra] Keynote: PHP-7
PHP Experience 2016 - [Palestra] Keynote: PHP-7PHP Experience 2016 - [Palestra] Keynote: PHP-7
PHP Experience 2016 - [Palestra] Keynote: PHP-7
 
Java script aula 02 - operadores
Java script   aula 02 - operadoresJava script   aula 02 - operadores
Java script aula 02 - operadores
 
Java script aula 05 - funções
Java script   aula 05 - funçõesJava script   aula 05 - funções
Java script aula 05 - funções
 
Java script aula 08 - formulários
Java script   aula 08 - formuláriosJava script   aula 08 - formulários
Java script aula 08 - formulários
 
Python 03
Python 03Python 03
Python 03
 
Desenvolvimento ágil com Kohana framework
Desenvolvimento ágil com Kohana frameworkDesenvolvimento ágil com Kohana framework
Desenvolvimento ágil com Kohana framework
 
Introdução à MEAN Stack
Introdução à MEAN StackIntrodução à MEAN Stack
Introdução à MEAN Stack
 
Python 04
Python 04Python 04
Python 04
 
Nossa experiência com TDD
Nossa experiência com TDDNossa experiência com TDD
Nossa experiência com TDD
 
Perl Moderno, dia3
Perl Moderno, dia3Perl Moderno, dia3
Perl Moderno, dia3
 
PHP para Adultos: Clean Code e Object Calisthenics
PHP para Adultos: Clean Code e Object CalisthenicsPHP para Adultos: Clean Code e Object Calisthenics
PHP para Adultos: Clean Code e Object Calisthenics
 
Python 07
Python 07Python 07
Python 07
 
Java script - funções
Java script - funçõesJava script - funções
Java script - funções
 
Silex 101
Silex 101Silex 101
Silex 101
 
PHP Jedi - Boas Práticas e Alta Performance
PHP Jedi - Boas Práticas e Alta PerformancePHP Jedi - Boas Práticas e Alta Performance
PHP Jedi - Boas Práticas e Alta Performance
 
Java 8 - Afinal onde usamos no dia a dia? GOJava 15 anos!
Java 8 - Afinal onde usamos no dia a dia? GOJava 15 anos!Java 8 - Afinal onde usamos no dia a dia? GOJava 15 anos!
Java 8 - Afinal onde usamos no dia a dia? GOJava 15 anos!
 
Funcao PHP
Funcao PHPFuncao PHP
Funcao PHP
 

Destaque

Destaque (6)

Docker: uma visão geral
Docker: uma visão geralDocker: uma visão geral
Docker: uma visão geral
 
Docker compose
Docker composeDocker compose
Docker compose
 
Design patterns de uma vez por todas
Design patterns de uma vez por todasDesign patterns de uma vez por todas
Design patterns de uma vez por todas
 
How to add Youtube Videos to SlideShare Presentations
How to add Youtube Videos to SlideShare PresentationsHow to add Youtube Videos to SlideShare Presentations
How to add Youtube Videos to SlideShare Presentations
 
YouTube videos inside SlideShare
YouTube videos inside SlideShareYouTube videos inside SlideShare
YouTube videos inside SlideShare
 
YouTube Powerpoint
YouTube PowerpointYouTube Powerpoint
YouTube Powerpoint
 

Semelhante a Código legado otimização

Qualidade no desenvolvimento de software com PHPUnit
Qualidade no desenvolvimento de software com PHPUnitQualidade no desenvolvimento de software com PHPUnit
Qualidade no desenvolvimento de software com PHPUnitDiego Tremper
 
Memcached, Gearman e Sphinx
Memcached, Gearman e SphinxMemcached, Gearman e Sphinx
Memcached, Gearman e SphinxElton Minetto
 
Técnicas para preparação e desenvolvimento de sites em django
Técnicas para preparação e desenvolvimento de sites em djangoTécnicas para preparação e desenvolvimento de sites em django
Técnicas para preparação e desenvolvimento de sites em djangoMario Chaves
 
PHPSP TestFest 2009
PHPSP TestFest 2009PHPSP TestFest 2009
PHPSP TestFest 2009Rafael Dohms
 
Aula 02 - Introdução ao PHP - Programação Web
Aula 02  - Introdução ao PHP - Programação WebAula 02  - Introdução ao PHP - Programação Web
Aula 02 - Introdução ao PHP - Programação WebDalton Martins
 
Programando para programadores: Desafios na evolução de um Framework
Programando para programadores: Desafios na evolução de um FrameworkProgramando para programadores: Desafios na evolução de um Framework
Programando para programadores: Desafios na evolução de um FrameworkPablo Dall'Oglio
 
Entre na fila. Processamento distribuído usando Gearman
Entre na fila. Processamento distribuído usando GearmanEntre na fila. Processamento distribuído usando Gearman
Entre na fila. Processamento distribuído usando GearmanElton Minetto
 
Ecommerce, mais simples do que parece
Ecommerce, mais simples do que pareceEcommerce, mais simples do que parece
Ecommerce, mais simples do que pareceImpacta Eventos
 
Deploy Heroku
Deploy HerokuDeploy Heroku
Deploy HerokuCreditas
 
Programando Melhor - Flisol
Programando Melhor - FlisolProgramando Melhor - Flisol
Programando Melhor - FlisolLeonn Leite
 
TDD em django sem desculpas versao fisl
TDD em django sem desculpas versao fislTDD em django sem desculpas versao fisl
TDD em django sem desculpas versao fislAdriano Petrich
 
Dockerizando aplicações em uma fintech o bom, o mau e o feio as surpresas
Dockerizando aplicações em uma fintech  o bom, o mau e o feio as surpresasDockerizando aplicações em uma fintech  o bom, o mau e o feio as surpresas
Dockerizando aplicações em uma fintech o bom, o mau e o feio as surpresasRafael Gomes
 
Introdução ao Zend Framework 2
Introdução ao Zend Framework 2Introdução ao Zend Framework 2
Introdução ao Zend Framework 2Elton Minetto
 
PHPUnit e teste de software
PHPUnit e teste de softwarePHPUnit e teste de software
PHPUnit e teste de softwarericardophp
 
Docker API Client with PHP and PYTHON
Docker API Client with PHP and PYTHONDocker API Client with PHP and PYTHON
Docker API Client with PHP and PYTHONIago Machado
 

Semelhante a Código legado otimização (20)

Dev Ext PHP
Dev Ext PHPDev Ext PHP
Dev Ext PHP
 
Qualidade no desenvolvimento de software com PHPUnit
Qualidade no desenvolvimento de software com PHPUnitQualidade no desenvolvimento de software com PHPUnit
Qualidade no desenvolvimento de software com PHPUnit
 
Memcached, Gearman e Sphinx
Memcached, Gearman e SphinxMemcached, Gearman e Sphinx
Memcached, Gearman e Sphinx
 
Técnicas para preparação e desenvolvimento de sites em django
Técnicas para preparação e desenvolvimento de sites em djangoTécnicas para preparação e desenvolvimento de sites em django
Técnicas para preparação e desenvolvimento de sites em django
 
Ganhando tempo com casos de testes
Ganhando tempo com casos de testesGanhando tempo com casos de testes
Ganhando tempo com casos de testes
 
PHPSP TestFest 2009
PHPSP TestFest 2009PHPSP TestFest 2009
PHPSP TestFest 2009
 
Aula 02 - Introdução ao PHP - Programação Web
Aula 02  - Introdução ao PHP - Programação WebAula 02  - Introdução ao PHP - Programação Web
Aula 02 - Introdução ao PHP - Programação Web
 
Programando para programadores: Desafios na evolução de um Framework
Programando para programadores: Desafios na evolução de um FrameworkProgramando para programadores: Desafios na evolução de um Framework
Programando para programadores: Desafios na evolução de um Framework
 
Entre na fila. Processamento distribuído usando Gearman
Entre na fila. Processamento distribuído usando GearmanEntre na fila. Processamento distribuído usando Gearman
Entre na fila. Processamento distribuído usando Gearman
 
Ecommerce, mais simples do que parece
Ecommerce, mais simples do que pareceEcommerce, mais simples do que parece
Ecommerce, mais simples do que parece
 
Ecommerce, mais simples do que parece
Ecommerce, mais simples do que pareceEcommerce, mais simples do que parece
Ecommerce, mais simples do que parece
 
Deploy Heroku
Deploy HerokuDeploy Heroku
Deploy Heroku
 
Programando Melhor - Flisol
Programando Melhor - FlisolProgramando Melhor - Flisol
Programando Melhor - Flisol
 
TDD em django sem desculpas versao fisl
TDD em django sem desculpas versao fislTDD em django sem desculpas versao fisl
TDD em django sem desculpas versao fisl
 
Pdo do PHP Palestra
Pdo do PHP PalestraPdo do PHP Palestra
Pdo do PHP Palestra
 
Php FrameWARks - sem CakePHP
Php FrameWARks - sem CakePHPPhp FrameWARks - sem CakePHP
Php FrameWARks - sem CakePHP
 
Dockerizando aplicações em uma fintech o bom, o mau e o feio as surpresas
Dockerizando aplicações em uma fintech  o bom, o mau e o feio as surpresasDockerizando aplicações em uma fintech  o bom, o mau e o feio as surpresas
Dockerizando aplicações em uma fintech o bom, o mau e o feio as surpresas
 
Introdução ao Zend Framework 2
Introdução ao Zend Framework 2Introdução ao Zend Framework 2
Introdução ao Zend Framework 2
 
PHPUnit e teste de software
PHPUnit e teste de softwarePHPUnit e teste de software
PHPUnit e teste de software
 
Docker API Client with PHP and PYTHON
Docker API Client with PHP and PYTHONDocker API Client with PHP and PYTHON
Docker API Client with PHP and PYTHON
 

Código legado otimização

  • 1. CÓDIGO LEGADO Michael Granados / @dgmike
  • 2. MICHAEL GRANADOS Conversor de sonhos de grandes investidores em realidade
  • 3. AGENDA WTF? A vítima Versionamento Pacotes, pacotes, pacotes... Um grupo, um código Testes Programação Calistênica
  • 10. WTF? Código não orientado a objetos
  • 13. CÓDIGO LEGADO! To me, legacy code is simply code without tests. Michael Feathers
  • 15. COMECE AGORA! csv subversion (svn) mercurial (hg) git
  • 16. PARE DE TRABALHAR NO SERVIDOR! Tenha uma cópia do projeto em sua máquina $ cd projeto_que_fiz_download $ git init $ git add . $ git commit -m "Importando projeto para o git"
  • 17. AHH.... MAS EU TENHO MEDO DESSA "TELA PRETA" Chega de desculpas: TortoiseGit
  • 19. LOG DE ATIVIDADES $ git log --oneline -n 10 0b66a73 Adding stepup uptater 207d43f Updating phpdocumentor to get last corrections 6015990 creating make file d54aafa some doc misc b2a8726 misc c8c3624 Documentor settings 70697d4 Adding phpdocumentor to dev 239f47d Merge pull request #16 from dgmike/enhancement/#14 bf53652 "method" implementation f3653c8 "method" signature
  • 20. O QUE MUDOU? $ git diff --name-only b2a8726..HEAD .stepuprc Makefile composer.json src/Apolo.php src/Route.php
  • 21. FUNCIONA SOMENTE NA MINHA MÁQUINA? github gitlab bitbucket No seu servidor linux (git init --bare / gitosis) Na máquina do seu amigo (via ip de rede + ssh)
  • 22. NOVO FLUXO DE TRABALHO
  • 23. PACOTES, PACOTES, PACOTES... Iremos precisar de ferramentas que irão nos auxiliar ao longo de nossa jornada. Fazer download do zip e descompactar é tão anos 90... Utilize algum gerenciador de pacotes: pear, composer, npm, bower
  • 24. UTILIZAREMOS COMPOSER Fácil de instalar $ curl -sS https://getcomposer.org/installer | php
  • 25. UTILIZAREMOS COMPOSER Fácil de usar // composer.json { "require": { "monolog/monolog": "1.2.*" } } $ php composer.phar install
  • 26. UTILIZAREMOS COMPOSER Usar em sua aplicação require 'vendor/autoload.php';
  • 27. UM GRUPO, UM CÓDIGO
  • 28. UM GRUPO, UM CÓDIGO function dinheiro($valor) { return 'R$ ' . number_format( $valor, 2, '.', '' ); } function precoComDesconto ($produtos, $codigo_promocional = false) { $total = 0; foreach ( $produtos as $produto ) { $total += $produto['preco_final']; } $porcentagem = 0; if ( count($produtos) == 2 ) {
  • 29. UM GRUPO, UM CÓDIGO Tabs vs Espaços? 2 ou 4 espaços? Final de linha? mac, linux, windows?
  • 31. EDITORCONFIG.ORG # .editorconfig # top-most EditorConfig file root = true # Unix-style newlines with a newline ending every file [*] end_of_line = lf insert_final_newline = true # Matches multiple files with brace expansion notation # Set default charset [*.{js,py}] charset = utf-8 # 4 space indentation [*.php] indent_style = space indent_size = 4
  • 32. CODESNIFFER // composer.json { "require-dev": { "squizlabs/php_codesniffer": "*" } } $ composer install
  • 33. CODESNIFFER $ ./vendor/bin/phpcs --standard=PSR2 funcoes.php FILE: ./funcoes.php -------------------------------------------------------------------------------- FOUND 16 ERROR(S) AFFECTING 10 LINE(S) -------------------------------------------------------------------------------- 7 | ERROR | Expected "foreach (...) {n"; found "foreach(...)n {n" 7 | ERROR | Space found after opening bracket of FOREACH loop 7 | ERROR | Space found before closing bracket of FOREACH loop 7 | ERROR | Expected 0 spaces after opening bracket; 1 found 7 | ERROR | Expected 0 spaces before closing bracket; 1 found 30 | ERROR | Expected "if (...) {n"; found "if (...)n {n" 34 | ERROR | Opening parenthesis of a multi-line function call must be the | | last content on the line 36 | ERROR | Closing parenthesis of a multi-line function call must be on a | | line by itself 47 | ERROR | Expected "function abc(...)"; found "function abc (...)" 47 | ERROR | Expected 0 spaces between argument "$codigo_promocional" and | | closing bracket; 1 found 47 | ERROR | Opening brace should be on a new line
  • 34. CODESNIFFER function dinheiro($valor) { return 'R$ ' . number_format( $valor, 2, '.', '' ); } function precoComDesconto ($produtos, $codigo_promocional = false) { $total = 0; foreach ( $produtos as $produto ) { $total += $produto['preco_final']; } $porcentagem = 0; if ( count($produtos) == 2 ) {
  • 35. CODESNIFFER function dinheiro($valor) { return 'R$ ' . number_format($valor, 2, '.', ''); } function precoComDesconto($produtos, $codigo_promocional = false) { $total = 0; foreach ($produtos as $produto) { $total += $produto['preco_final']; } $porcentagem = 0; if (count($produtos) == 2) { $porcentagem = 5; $total = $total - ($total * 5/100);
  • 36. TESTES function calculaJuros($produtos, $juros) { echo '<pre>'; print_r($produtos); echo '</pre>'; // teste $total = 0; foreach($produtos as $produto) { $total += $produto['valor_real']; } $total = $total + ($total * $juros / 100); die($total); // teste return $total; }
  • 37. TESTES Pacotes: PHPUnit, SimpleTest Tipos: unitários, integração, aceitacao
  • 38. SIMPLETEST $ php composer.phar require --dev "lastcraft/simpletest:*"
  • 39. SIMPLETEST define('SIMPLETEST_DIR', realpath(__DIR__ . '/../../vendor/lastcraft/simpletest')); require SIMPLETEST_DIR . '/autorun.php'; require SIMPLETEST_DIR . '/web_tester.php'; class TestIndex extends WebTestCase { function testHomePage() { $this->assertTrue($this->get('http://localhost:3001')); $this->assertText('Loja Legado'); } function testCliqueComprarAdicionaLinkCarrinhoDeCompras() { $this->assertTrue($this->get('http://localhost:3001')); $this->assertNoText('Carrinho de compras');
  • 40. SIMPLETEST $ php tests/aceitacao/test_index.php test_index.php OK Test cases run: 1/2, Passes: 13, Failures: 0, Exceptions: 0 test_index.php 1) Text [texto inexistente] not detected in [String: Loja Legado Loja Legado Loja Legado Carrinho de compras in testCliqueComprarAdicionaLinkCarrinhoDeCompras in TestIndex FAILURES!!! Test cases run: 1/2, Passes: 12, Failures: 1, Exceptions: 0
  • 41. PHPUNIT $ php composer.phar require --dev 'phpunit/phpunit:*'
  • 42. PHPUNIT require_once __DIR__ . '/../../funcoes.php'; class FuncoesTest extends PHPUnit_Framework_TestCase { public function testDinheiro() { $dinheiro = dinheiro(24); $this->assertEquals('R$ 24,00', $dinheiro); } }
  • 43. PHPUNIT $ ./vendor/bin/phpunit tests/unitarios/funcoes_test.php PHPUnit 4.3.5 by Sebastian Bergmann. .. Time: 33 ms, Memory: 3.00Mb OK (2 tests, 4 assertions)
  • 44. PHPUNIT $ ./vendor/bin/phpunit --testdox tests/unitarios/funcoes_test.php PHPUnit 4.3.5 by Sebastian Bergmann. Funcoes [x] Dinheiro [x] Preco com desconto $ ./vendor/bin/phpunit --tap tests/unitarios/funcoes_test.php TAP version 13 ok 1 - FuncoesTest::testDinheiro ok 2 - FuncoesTest::testPrecoComDesconto 1..2
  • 45. PHPUNIT O que dá pra fazer? Mock/Stub Pre-popular banco de dados CodeCoverage Selenium
  • 47. PROGRAMAÇÃO CALISTÊNICA é uma forma de atividade que consiste em uma Calistenia variedade de exercícios físicos feitos sem equipamentos ou pesos que têm por objetivo aumentar a força e a flexibilidade usando o peso do próprio corpo como resistência Jeff Bay escreveu um artigo no livro "The ThoughtWorks Antology" entitulado "Object Calisthenics". Ele propõe um exercício "calistênico" para melhorar o design de software e ajudar a internalizar princípios de bom design de programação orientada a objetos
  • 48. ALGUNS PONTOS RELEVANTES! PHP não é JAVA!!! Algumas alterações serão feitas! São apenas dicas e não regras!
  • 49. REGRAS DO EXERCÍCIO 1. Use apenas um nível de identação por método 2. Não use else 3. Crie objetos para tipos primitivos e strings 4. Use apenas um ponto por linha 5. Não abrevie 6. Mantenha todas as entidades pequenas 7. Não use classes com mais de duas variáveis instanciadas 8. Não use coleções de primeira-classe 9. Não use Getters/Setters/Properties
  • 50. USE APENAS UM NÍVEL DE IDENTAÇÃO POR MÉTODO function ganho($registros) { $ganhosTotais = 0; foreach($registros as $registro) { foreach ($registro['produtos'] as $produto) { $ganhosTotais += $produto['valor_real'] - $produto['valor_compra']; } } return $ganhosTotais; }
  • 51. USE APENAS UM NÍVEL DE IDENTAÇÃO POR MÉTODO function ganho($registros) { $ganhosTotais = 0; foreach($registros as $registro) { $ganhosTotais += ganhosPorRegistro($registro); } return $ganhosTotais; } function ganhosPorRegistro($registro) { $ganhos = 0; foreach ($registro['produtos'] as $produto) { $ganhos += $produto['valor_real'] - $produto['valor_compra']; } return $ganhos; }
  • 52. NUNCA USE ELSE function precoFinal($produto) { if ($produto['desconto'] > 0) { $precoFinal = $produto['preco'] - ($produto['preco'] * $produto['desconto'] / 100); } else { $precoFinal = $produto['preco']; } return $precoFinal; }
  • 53. NUNCA USE ELSE function precoFinal($produto) { if ($produto['desconto'] > 0) { return $produto['preco'] - ($produto['preco'] * $produto['desconto'] / 100); } return $precoFinal = $produto['preco']; } Outro exemplo function precoFinal($produto) { $precoFinal = $produto['preco']; if ($produto['desconto'] > 0) { $precoFinal = $produto['preco'] - ($produto['preco'] * $produto['desconto'] / 100); } return $precoFinal; }
  • 54. CRIE OBJETOS PARA TIPOS PRIMITIVOS E STRINGS SE ELES POSSUIREM ALGUM COMPORTAMENTO
  • 55. CRIE OBJETOS PARA TIPOS PRIMITIVOS E STRINGS SE ELES POSSUIREM ALGUM COMPORTAMENTO function desconto(array $produtos, $desconto) { $total = 0; foreach($produtos as $produto) { $total += $produto['valor_real']; } return $total - ($total * $desconto / 100); }
  • 56. CRIE OBJETOS PARA TIPOS PRIMITIVOS E STRINGS SE ELES POSSUIREM ALGUM COMPORTAMENTO class ProdutosLista { protected $produtos; public function __construct(array $produtos) { $this->produtos = $produtos; } public function valor_real_total() { $total = 0; foreach ($this->produtos as $produto) { $total += $produto['valor_real']; } return $total; } }
  • 57. CRIE OBJETOS PARA TIPOS PRIMITIVOS E STRINGS SE ELES POSSUIREM ALGUM COMPORTAMENTO class Numeral { protected $valor; public function __construct($valorInicial = 0) { $this->valor = $valorInicial; } public function valor() { return $this->valor; } public function adiciona(Numeral $valor) { $this->valor += $valor->valor(); } public function removerPercentual(Numeral $percentual) { $this->valor -= $this->valor() * $percentual / 100; } }
  • 58. CRIE OBJETOS PARA TIPOS PRIMITIVOS E STRINGS SE ELES POSSUIREM ALGUM COMPORTAMENTO function desconto(ProdutosLista $produtos, Numeral $desconto) { $total = new Numeral($produtos->valor_real_total()); $total->removerPercentual($desconto); return $total; }
  • 59. USE APENAS UM PONTO ( -> ) POR LINHA SE NÃO FOR UM ENCADEAMENTO OU UM GETTER
  • 60. USE APENAS UM ( -> ) POR LINHA SE NÃO FOR UM ENCADEAMENTO OU UM GETTER function categoria(ProdutoLista $produtos) { return $produtos->primeiro->categoria->nome->humanizado(); }
  • 61. USE APENAS UM ( -> ) POR LINHA SE NÃO FOR UM ENCADEAMENTO OU UM GETTER function categoria(ProdutoLista $produtos) { $categoria = $produtos->primeiraCategoria(); $template = $categoria->decorator(new HumanizadoDecorator); return $template->renderiza(); }
  • 62. USE APENAS UM ( -> ) POR LINHA SE NÃO FOR UM ENCADEAMENTO OU UM GETTER $this possui um valor especial no PHP class Produtos { protected $produtos; public function primeiraCategoria() { // em java: primeiroProduto.categoria() return $this->primeiroProduto->categoria(); } }
  • 63. USE APENAS UM ( -> ) POR LINHA SE NÃO FOR UM ENCADEAMENTO OU UM GETTER $this possui um valor especial no PHP $filtros->adicionaImagem($imagem) ->adicionarFiltro(new PretoBranco) ->adicionarFiltro(new BordaMadeira);
  • 65. ESTÁ ESCREVENDO A MESMA VARIÁVEL MUITAS VEZES? Parece que temos um código reutilizado várias vezes. Talvez tenhamos duplicação de código
  • 66. O NOME DO MÉTODO ESTÁ MUITO GRANDE? Talvez sua classe/metodo está executando mais do que deveria. Talvez tenhamos um problema de responsabilidade
  • 67. MANTENHA TODAS AS ENTIDADES PEQUENAS Nada de classes com mais de 50 linhas Nada de pacotes/diretórios com mais de 10 arquivos
  • 68. MANTENHA TODAS AS ENTIDADES PEQUENAS Nada de classes com mais de 100 linhas Nada de pacotes/diretórios com mais de 15 arquivos
  • 69. NÃO USE CLASSES COM MAIS DE DUAS VARIÁVEIS INSTANCIADAS
  • 71. NÃO USE CLASSES COM MAIS DE CINCO VARIÁVEIS INSTANCIADAS
  • 72. USE COLEÇÕES COMO PRIMEIRA-CLASSE class Usuario { protected $fotos = array(); protected $nome = ''; public function nome() { return $this->nome; } public function linkFotos() { $links = array(); foreach($this->fotos as $foto) { $links[] = $foto['link']; } return implode("n", $links); } }
  • 73. USE COLEÇÕES COMO PRIMEIRA-CLASSE class Usuario { protected $fotos = null; protected $nome = ''; public function nome() { return $this->nome; } public function fotos() { return $this->fotos; } } ListaFotos { protected $fotos = array(); }
  • 74. USE COLEÇÕES COMO PRIMEIRA-CLASSE $fotos->filtrar(...); $fotos->mapear(...); $fotos->adicionar(...); $fotos->original(...);
  • 75. NÃO USE GETTERS/SETTERS class Pessoa { protected $nome; public getNome() { return $this->nome; } public setNome($nome) { $this->nome = $nome; } }
  • 76. USE GETTERS/SETTERS class Pessoa { protected $nome; public getNome() { return $this->nome; } public maiusculizaNome() { $this->nome = strtoupper($this->nome); } }
  • 77. SURPRESA! DOCUMENTE SEU CÓDIGO // verifica se tem mais de 20 produtos if ($produtos->total() > 20) { $produtos->aplicaDesconto(new Desconto(10)); }
  • 78. DOCUMENTE SEU CÓDIGO // resgata somente fotos ativas $fotos = array_map( $fotos->filter('ativos'), create_function('$foto', 'return $foto["link"];') ); Não explique um código ruim, corrijá-o! $fotos->filter('ativos')->links();
  • 79. PHPDOC /** * Verifica se as credenciais do usuário estão corretas * * @todo implementar conexao com banco de dados * @param String $email Email do usuario * @param String $senha Senha do usuario * * @return Boolean */ function verificaLogin(String $email, String $senha) { // ... }
  • 80. DÚVIDAS? Seu momento de me deixar sem graça! ;-)
  • 81. OBRIGADO! @dgmike - http://www.slideshare.net/dgmike