Object Calisthenics: relaxe e escreva códigos simples Goiânia, 23 de Março de 2013 Otávio Calaça Xavier [email protected]
Object Calisthenics:relaxe e escreva
códigos simples
Goiânia, 23 de Março de 2013
Otávio Calaça Xavier
Criado em dezembro de 2007; Lista de Discussão:
− Mais de 650 membros.
Projetos:− Encontros mensais;− Softwares Livres em PHP;− Networking.
Eventos:• FLISOL, FGSL, Latinoware, Conisli, CONSOFT, PHP
Conference Brasil, FISL, Join Community …
Precisamos de Colaboradores!!!
Grupo de Desenvolvedores PHP de Goiás
www.gophp.org.br
3
Object Calisthenics: relaxe e escreva códigos simples
Roteiro
• Motivação;
• Orientações;
• Aplicação.
4
Object Calisthenics: relaxe e escreva códigos simples
Por que meu código é ruim?
• Ele é legível?• Ele é testável?• Ele é de fácil manutenção?• Ele é reusável?
5
Object Calisthenics: relaxe e escreva códigos simples
Object Calisthenics
• Calistenia = exercício de relaxamento; ginástica rítimica;
• Uma variedade de exercícios simples e rítimicos para alcançar melhor qualidade de código e OO.
6
Object Calisthenics: relaxe e escreva códigos simples
Object Calisthenics
• Jeff Bay em The ThoughtWorks Anthology definiu o termo Object Calisthenics para a computação, como o conjunto de exercícios para a programação Orientada a Objetos.
7
Object Calisthenics: relaxe e escreva códigos simples
Object Calisthenics
• Orientações:– Nove (9) orientações simples e que
podem ser utilizadas em qualquer linguagem orientada a objetos.
8
Object Calisthenics: relaxe e escreva códigos simples
ORIENTAÇÃO I
somente um nível de identação/recuo por método.
9
Object Calisthenics: relaxe e escreva códigos simples
ORIENTAÇÃO I somente um nível de identação/recuo por método
public function validarProdutos($produtos) { $camposRequeridos = array( 'nome', 'preco', 'descricao', 'tipo' ); $valido = true; foreach($produtos as $produto) { $campos = array_keys($produto); foreach ($camposRequeridos as $campoRequerido) { if(!in_array($campoRequerido, $campos)) { $valido = false; } } } return $valido; }
10
Object Calisthenics: relaxe e escreva códigos simples
ORIENTAÇÃO I somente um nível de identação/recuo por método
public function validarProdutos($produtos) { $camposRequeridos = array( 'nome', 'preco', 'descricao', 'tipo' ); $valido = true; foreach($produtos as $produto) { $campos = array_keys($produto); foreach ($camposRequeridos as $campoRequerido) { if(!in_array($campoRequerido, $campos)) { $valido = false; } } } return $valido; }
11
Object Calisthenics: relaxe e escreva códigos simples
ORIENTAÇÃO I somente um nível de identação/recuo por método
public function validarProdutos($produtos) { $camposRequeridos = array( 'nome', 'preco', 'descricao', 'tipo' ); $valido = true; foreach($produtos as $produto) { $campos = array_keys($produto); foreach ($camposRequeridos as $campoRequerido) { if(!in_array($campoRequerido, $campos)) { $valido = false; } } } return $valido; }
0
12
3
12
Object Calisthenics: relaxe e escreva códigos simples
ORIENTAÇÃO I somente um nível de identação/recuo por método
public function validarProdutos($produtos) { $camposRequeridos = array( 'nome', 'preco', 'descricao', 'tipo' ); $valido = true; foreach($produtos as $produto) { $validacao = $this->validarProdutoIndividual($produto, $camposRequeridos); if( ! $validacao) { $valido = false; } } return $valido; } public function validarProdutoIndividual($produto, $camposRequeridos) { $valido = true; $campos = array_keys($produto); foreach ($camposRequeridos as $campoRequerido) { if( ! in_array($campoRequerido, $campos)) { $valido = false; } } }
13
Object Calisthenics: relaxe e escreva códigos simples
ORIENTAÇÃO I somente um nível de identação/recuo por método
public function validarProdutos($produtos) { $camposRequeridos = array( 'nome', 'preco', 'descricao', 'tipo' ); $valido = true; foreach($produtos as $produto) { $validacao = $this->validarProdutoIndividual($produto, $camposRequeridos); if( ! $validacao) { $valido = false; } } return $valido; } public function validarProdutoIndividual($produto, $camposRequeridos) { $valido = true; $campos = array_keys($produto); foreach ($camposRequeridos as $campoRequerido) { if( ! in_array($campoRequerido, $campos)) { $valido = false; } } }
14
Object Calisthenics: relaxe e escreva códigos simples
ORIENTAÇÃO I somente um nível de identação/recuo por método
public function validarProdutos($produtos) { $camposRequeridos = array( 'nome', 'preco', 'descricao', 'tipo' ); $valido = true; foreach($produtos as $produto) { $validacao = $this->validarProdutoIndividual($produto, $camposRequeridos); if( ! $validacao) { $valido = false; } } return $valido; } public function validarProdutoIndividual($produto, $camposRequeridos) { $valido = true; $campos = array_keys($produto); foreach ($camposRequeridos as $campoRequerido) { if( ! in_array($campoRequerido, $campos)) { $valido = false; } } }
01
2
01
2
15
Object Calisthenics: relaxe e escreva códigos simples
ORIENTAÇÃO I somente um nível de identação/recuo por método
public function validarProdutos($produtos) { $camposRequeridos = array( 'nome', 'preco', 'descricao', 'tipo' ); foreach($produtos as $produto) { if( ! $this->validarProdutoIndividual($produto, $camposRequeridos)) { return false; } } return true; } public function validarProdutoIndividual($produto, $camposRequeridos) { $campos = array_keys($produto); $camposEsquecidos = array_diff($camposRequeridos, $campos); return (count($camposEsquecidos) == 0); }
16
Object Calisthenics: relaxe e escreva códigos simples
ORIENTAÇÃO I somente um nível de identação/recuo por método
public function validarProdutos($produtos) { $camposRequeridos = array( 'nome', 'preco', 'descricao', 'tipo' ); foreach($produtos as $produto) { if( ! $this->validarProdutoIndividual($produto, $camposRequeridos)) { return false; } } return true; } public function validarProdutoIndividual($produto, $camposRequeridos) { $campos = array_keys($produto); $camposEsquecidos = array_diff($camposRequeridos, $campos); return (count($camposEsquecidos) == 0); }
01
2
17
Object Calisthenics: relaxe e escreva códigos simples
ORIENTAÇÃO I somente um nível de identação/recuo por método
public function validarProdutos($produtos) { $produtosInvalidos = array_filter($produtos, 'verificaProdutoInvalido'); return (count($produtosInvalidos) === 0); } public function verificaProdutoInvalido($produto) { $camposRequeridos = array( 'nome', 'preco', 'descricao', 'tipo' ); $campos = array_keys($produto); $camposEsquecidos = array_diff($camposRequeridos, $campos); return (count($camposEsquecidos) > 0); }
18
Object Calisthenics: relaxe e escreva códigos simples
ORIENTAÇÃO I somente um nível de identação/recuo por método
class Board { ... String board() { StringBuffer buf = new StringBuffer(); for (int i = 0; i < 10; i++) { for (int j = 0; j < 10; j++) { buf.append(data[i][j]); } buf.append(“\n”); } return buf.toString(); }}
19
Object Calisthenics: relaxe e escreva códigos simples
ORIENTAÇÃO I somente um nível de identação/recuo por método
class Board { ... String board() { StringBuffer buf = new StringBuffer(); for (int i = 0; i < 10; i++) { for (int j = 0; j < 10; j++) { buf.append(data[i][j]); } buf.append(“\n”); } return buf.toString(); }}
01
2
20
Object Calisthenics: relaxe e escreva códigos simples
ORIENTAÇÃO I somente um nível de identação/recuo por método
class Board { ... String board() { StringBuffer buf = new StringBuffer(); collectRows(buf); return buf.toString(); } void collectRows(StringBuffer buf) { for (int i = 0; i < 10; i++) { collectRow(buf, i); } } void collectRow(StringBuffer buf, int row) { for (int i = 0; i < 10; i++) { Buf.append(data[row][i]); } buf.append(“\n”); }}
21
Object Calisthenics: relaxe e escreva códigos simples
ORIENTAÇÃO I somente um nível de identação/recuo por método
• Benefícios:
– Maior coesão;
– Reduz a complexidade ciclomática;
– Métodos acabam fazendo apenas uma coisa, como deve ser;
– Aumenta a reusabilidade.
22
Object Calisthenics: relaxe e escreva códigos simples
ORIENTAÇÃO II
não utilize a palavra-chave else.
23
Object Calisthenics: relaxe e escreva códigos simples
ORIENTAÇÃO II não utilize a palavra-chave else
public function login() { $usuario = $this->input()->post('usuario'); $senha = $this->input()->post('senha'); $referencia = $this->input()->post('referencia'); if($this->usuariosModel->verificaPermissao($usuario, $senha)) { redirect($referencia); } else { $this->session->setFlashData('erro', 'Usuário ou senha inválidos.'); $this->session->setFlashData('referencia', $referencia); redirect('login'); } }
24
Object Calisthenics: relaxe e escreva códigos simples
ORIENTAÇÃO II não utilize a palavra-chave else
public function login() { $usuario = $this->input()->post('usuario'); $senha = $this->input()->post('senha'); $referencia = $this->input()->post('referencia'); if($this->usuariosModel->verificaPermissao($usuario, $senha)) { redirect($referencia); } else { $this->session->setFlashData('erro', 'Usuário ou senha inválidos.'); $this->session->setFlashData('referencia', $referencia); redirect('login'); } }
25
Object Calisthenics: relaxe e escreva códigos simples
ORIENTAÇÃO II não utilize a palavra-chave else
public function login() { $usuario = $this->input()->post('usuario'); $senha = $this->input()->post('senha'); $referencia = $this->input()->post('referencia'); if( ! $this->usuariosModel->verificaPermissao($usuario, $senha)) { $this->session->setFlashData('erro', 'Usuário ou senha inválidos.'); $this->session->setFlashData('referencia', $referencia); $referencia = 'login'; }
redirect($referencia); }
26
Object Calisthenics: relaxe e escreva códigos simples
ORIENTAÇÃO II não utilize a palavra-chave else
• Benefícios:
– Ajuda a prevenir duplicação de código;
– Reduz a complexidade ciclomática;
– Faz o código ficar mais limpo, passando por um único caminho.
27
Object Calisthenics: relaxe e escreva códigos simples
ORIENTAÇÃO III
encapsule todos os tipos primitivos e strings.
28
Object Calisthenics: relaxe e escreva códigos simples
ORIENTAÇÃO III encapsule todos os tipos primitivos e strings
class Aluno { private int matricula; private boolean ativo; private long cpf; //... }
29
Object Calisthenics: relaxe e escreva códigos simples
ORIENTAÇÃO III encapsule todos os tipos primitivos e strings
class Aluno { private Integer matricula; private Boolean ativo; private Long cpf; //... }
30
Object Calisthenics: relaxe e escreva códigos simples
ORIENTAÇÃO III (ajuste)
encapsule todos os tipos primitivos e strings, se eles possuírem comportamento.
31
Object Calisthenics: relaxe e escreva códigos simples
ORIENTAÇÃO III encapsule os tipos primitivos e strings, se eles possuírem
comportamento
class UIComponent { //... public function repaint($animate = true) { //... }}//...$component->repaint(false);
32
Object Calisthenics: relaxe e escreva códigos simples
ORIENTAÇÃO III encapsule os tipos primitivos e strings, se eles possuírem
comportamento
class UIComponent { //... public function repaint(Animate $animate) { //... }}
class Animate { private $animate; public function __construct($animate = true) { $this->animate = true; }}//...$component->repaint( new Animate(false) );
33
Object Calisthenics: relaxe e escreva códigos simples
ORIENTAÇÃO III encapsule os tipos primitivos e strings, se eles possuírem
comportamento
• Benefícios:
– Indução de Tipo;
– Encapsulamento de operações.
34
Object Calisthenics: relaxe e escreva códigos simples
ORIENTAÇÃO IV
somente um ponto (“arrow” para o PHP) por linha.
35
Object Calisthenics: relaxe e escreva códigos simples
ORIENTAÇÃO IV(ajuste)
somente um ponto (“arrow” para o PHP) por linha, se não for
fluente.
36
Object Calisthenics: relaxe e escreva códigos simples
ORIENTAÇÃO IV somente um ponto por linha, se não for fluente
$filterChain->addFilter(new Zend_Filter_Alpha()) ->addFilter(new Zend_Filter_StringToLower());
listeners->addListener(new TimeListener()) ->addListener(new RestfulListener());
Não utilize:
$user->getLocation()->getCountry()->getName();
user.getAddress().getPostalConde();
$this->getRestService()->getJson($representations->find($url->getPath()));
this.getUsers().find(userId).getAddress().
37
Object Calisthenics: relaxe e escreva códigos simples
ORIENTAÇÃO IV somente um ponto por linha, se não for fluente
• Benefícios:
– Legibilidade;
– Construção de testes facilitada (mocks);
– Mais fácil para depurar;
38
Object Calisthenics: relaxe e escreva códigos simples
ORIENTAÇÃO V
não abrevie.
39
Object Calisthenics: relaxe e escreva códigos simples
ORIENTAÇÃO Vnão abrevie
• Por que você abrevia?– Preguiça de escrever o mesmo nome várias vezes...
• Talvez isso indique duplicidade de código!
– Preguiça de escrever o nome do método muito longo...• Talvez isso indique que o seu método faz mais de
uma coisa. Isso deve ser separado em vários métodos ou até classes!
40
Object Calisthenics: relaxe e escreva códigos simples
ORIENTAÇÃO Vnão abrevie
• Benefícios:
– Comunicação mais clara;
– Facilita a busca por problemas ocultos.
41
Object Calisthenics: relaxe e escreva códigos simples
ORIENTAÇÃO VI
mantenha suas entidades pequenas.
42
Object Calisthenics: relaxe e escreva códigos simples
ORIENTAÇÃO VImantenha suas entidades pequenas
• Regra original: – 50 linhas por classe.
• Regra adaptada: – 100 linhas por classe (para incluir os blocos de
documentação);– 15 classes por pacote/namespace/pasta;– De 15 a 20 linhas por método.
43
Object Calisthenics: relaxe e escreva códigos simples
ORIENTAÇÃO VImantenha suas entidades pequenas
• Benefícios:
– Responsabilidade única;
– Métodos objetivos;
– Pacotes/namespaces mais enxutos;
44
Object Calisthenics: relaxe e escreva códigos simples
ORIENTAÇÃO VII
não crie classes com mais de duas variáveis de instância.
45
Object Calisthenics: relaxe e escreva códigos simples
ORIENTAÇÃO VII(ajuste)
não crie classes com mais de cinco variáveis de instância.
46
Object Calisthenics: relaxe e escreva códigos simples
ORIENTAÇÃO VIInão crie classes com mais de cinco variáveis de instância.
• Benefícios:
– Lista reduzida de dependências;
– Mais fácil para fazer Mocking para testes.
47
Object Calisthenics: relaxe e escreva códigos simples
ORIENTAÇÃO VIII
use coleções de primeiro nível.
48
Object Calisthenics: relaxe e escreva códigos simples
ORIENTAÇÃO VIIIuse coleções de primeiro nível.
• Qualquer classe que contenha uma coleção (ou tenha esse propósito), não deve conter outras propriedades;
• Encapsulamento de coleções primitivas (arrays);
• Utilização de Interfaces Orientadas a Objetos:– Collections do Java;– SPL do PHP.
49
Object Calisthenics: relaxe e escreva códigos simples
ORIENTAÇÃO VIIIuse coleções de primeiro nível.
• Benefícios:
– É possível implementar operações em coleções;
– Utilizar métodos já existentes em interfaces pré-definidas;
50
Object Calisthenics: relaxe e escreva códigos simples
ORIENTAÇÃO IX
não crie métodos getter/setter para propriedades.
51
Object Calisthenics: relaxe e escreva códigos simples
ORIENTAÇÃO IX(removida)
não crie métodos getter/setter para propriedades.
52
Object Calisthenics: relaxe e escreva códigos simples
ORIENTAÇÃO IXcrie métodos getter/setter para propriedades
• Muitos frameworks utilizam os métodos getters e setters para inicializar variáveis, reduzindo código e evitando erros desnecessários.
• Não coloque nenhum tipo de regra de negócio nos getters e setters.
53
Object Calisthenics: relaxe e escreva códigos simples
ORIENTAÇÃO X (bônus)
documente seu código.
54
Object Calisthenics: relaxe e escreva códigos simples
Referências
• Object Calisthenics aplicado ao PHP– Guilherme Blanco
• You code sucks, let's fix it– Rafael Dohms
• The ThoughtWorks Anthology– Martin Fower
55
Object Calisthenics: relaxe e escreva códigos simples
FIM
Perguntas?
Obrigado!
Otávio Calaça Xavier
@otaviocx