O documento resume as orientações do método Object Calisthenics para escrever códigos simples e de alta qualidade. As orientações incluem: 1) usar apenas um nível de identação por método; 2) evitar usar a palavra-chave "else"; 3) encapsular tipos primitivos se tiverem comportamento.
Classe V: Educação à distância com Videoconferência no Moodle
Object Calisthenics: relaxe e escreva códigos simples
1. Object Calisthenics:
relaxe e escreva
códigos simples
Goiânia, 23 de Março de 2013
Otávio Calaça Xavier
otaviocx@gmail.com
2. 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
4. 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. 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. 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. 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.
9. 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. 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. 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
1
2
3
12. 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. 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. 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;
}
}
}
0
1
2
0
1
2
15. 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. 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);
}
0
1
2
17. 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. 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. 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();
}
}
0
1
2
20. 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. 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.
23. 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. 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. 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. 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.
28. 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. 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. 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. 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. 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. 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.
35. 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. 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. 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;
39. 39
Object Calisthenics: relaxe e escreva códigos simples
ORIENTAÇÃO V
nã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. 40
Object Calisthenics: relaxe e escreva códigos simples
ORIENTAÇÃO V
não abrevie
• Benefícios:
– Comunicação mais clara;
– Facilita a busca por problemas ocultos.
42. 42
Object Calisthenics: relaxe e escreva códigos simples
ORIENTAÇÃO VI
mantenha 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. 43
Object Calisthenics: relaxe e escreva códigos simples
ORIENTAÇÃO VI
mantenha suas entidades pequenas
• Benefícios:
– Responsabilidade única;
– Métodos objetivos;
– Pacotes/namespaces mais enxutos;
44. 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. 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. 46
Object Calisthenics: relaxe e escreva códigos simples
ORIENTAÇÃO VII
nã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.
48. 48
Object Calisthenics: relaxe e escreva códigos simples
ORIENTAÇÃO VIII
use 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. 49
Object Calisthenics: relaxe e escreva códigos simples
ORIENTAÇÃO VIII
use 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. 50
Object Calisthenics: relaxe e escreva códigos simples
ORIENTAÇÃO IX
não crie métodos getter/setter
para propriedades.
51. 51
Object Calisthenics: relaxe e escreva códigos simples
ORIENTAÇÃO IX
(removida)
não crie métodos getter/setter
para propriedades.
52. 52
Object Calisthenics: relaxe e escreva códigos simples
ORIENTAÇÃO IX
crie 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.