O documento discute técnicas e boas práticas para lidar com código legado, como versionamento, testes, organização do código e programação orientada a objetos. Algumas das técnicas discutidas incluem utilizar ferramentas como Git para versionamento, Composer para gerenciamento de pacotes, PHPUnit e SimpleTest para testes, EditorConfig para padronização de estilos e CodeSniffer para análises estáticas. O documento também apresenta a técnica de "Programação Calistênica" para melhorar o design do código.
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)
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
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
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);
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) {
// ...
}