Object Calisthenics
Dorian Neto
- Desenvolvedor desde 2011
- Fundador do DojoCE
- CTO na Prombox
- ZCPE ID: ZEND030288
Sumário
- Questionamento e Motivações
- Conceito
- Estudo das regras
Você está satisfeito com a qualidade do seu código?
Motivações
- Legibilidade
- Manutenabilidade
- Testabilidade
- Reusabilidade
Calisthenics é um termo grego = Exercício
Apenas um nível de indentação por método
protected function destroyFile(Model $record)
{
if (method_exists($record, 'getFileField')) {
$field = $record->getFileField();
$field = $record->$field;
if (!empty($field)) {
list($file, $extension) = explode('.', $field);
$extension = '.' . $extension;
$size = [
'',
'_150x150'
];
foreach ($size as $item) {
$file = $this->uploadPath . $file . $item . $extension;
if (File::exists($file)) {
File::delete($file);
}
}
}
}
}
1
2
3
0
protected function destroyFile(Model $record)
{
if (!method_exists($record, 'getFileField')) {
return null;
}
$field = $record->getFileField();
$field = $record->$field;
if (!empty($field)) {
list($file, $extension) = explode('.', $field);
$extension = '.' . $extension;
$size = [
'',
'_150x150'
];
foreach ($size as $item) {
$file = $this->uploadPath . $file . $item . $extension;
if (File::exists($file)) {
File::delete($file);
}
}
}
}
1
2
0
protected function destroyFile(Model $record)
{
if (!method_exists($record, 'getFileField')) {
return null;
}
$field = $record->getFileField();
$field = $record->$field;
if (empty($field)) {
return null;
}
list($file, $extension) = explode('.', $field);
$extension = '.' . $extension;
$size = [
'',
'_150x150'
];
foreach ($size as $item) {
$file = $this->uploadPath . $file . $item . $extension;
if (File::exists($file)) {
File::delete($file);
}
}
}
1
0
Não use o ELSE
public function authenticate(Request $request)
{
$credentials = array(
'email' => $request->email,
'password' => $request->senha
);
if (Auth::attempt($credentials)) {
$notice = [
'alert' => 'success',
'message' => trans('auth.success')
];
return Redirect::intended(route('dashboard'))
->with('notice', $notice);
} else {
$notice = [
'alert' => 'danger',
'message' => trans('auth.failed')
];
return Redirect::route('login.index')
->with('notice', $notice);
}
}
public function authenticate(Request $request)
{
$credentials = array(
'email' => $request->email,
'password' => $request->senha
);
$notice = [
'alert' => 'danger',
'message' => trans('auth.failed')
];
if (Auth::attempt($credentials)) {
$notice['alert'] = 'success';
$notice['message'] = trans('auth.success');
return Redirect::intended(route('dashboard'))
->with('notice', $notice);
}
return Redirect::route('login.index')
->with('notice', $notice);
}
Um único operador de objeto (->) por linha
$this->group->member->setName("Fulano")->getConfig()->invite();
$this->group->member->setName("Fulano")->getConfig()->invite();
$this->group
->addFilter(new Foo())
->addFilter(new Bar());
Exceto para Interface fluente e Query Builder
$this->group->member->setName("Fulano")->getConfig()->invite();
$this->group
->addFilter(new Foo())
->addFilter(new Bar());
$this->group
->where('id', 34)
->select(['name'])
->get();
Exceto para Interface fluente e Query Builder
Não abrevie!
public function calcNum(Group $group) {...}
public function calcNum(Group $group) {...}
public function totalMembers(Group $group) {...}
public function addMemberAndInviteToGroup(Member $member) {...}
public function addMemberAndInviteToGroup(Member $member) {...}
public function addMember(Member $member) {...}
if ($rjx === true) {...}
???
if ($rjx === true) {...}
if ($request_ajax === true) {...}
Mantenha suas classes pequenas
- Máximo de 200 linhas por classe (incluindo documentação)
- 10 métodos por classe
- Até 20 linhas por método
- 15 Classes por Namespaces (pasta)
Limite o número de atributos de instância numa classe (2 a 5)
class Group
{
protected $provider;
protected $member;
protected $school;
protected $helper;
protected $view;
protected $request;
}
class Group
{
protected $provider;
protected $member;
protected $school;
}
Não use getters e setters
define('KILL_THE_ENEMY', 1);
define('KILL_THE_BOSS', 5);
class Game
{
private $score = 0;
public function setScore($score)
{
$this->score = $score;
}
public function getScore()
{
return $this->score;
}
}
$player = new Game();
$player->setScore($player->getScore()+KILL_THE_BOSS);
Decisão está sendo tomada fora da classe
<?php
define('KILL_THE_ENEMY', 1);
define('KILL_THE_BOSS', 5);
class Game
{
private $score = 0;
public function addScore($score)
{
$this->score += $score;
}
}
$player = new Game();
$player->addScore(KILL_THE_BOSS);
<?php
define('KILL_THE_ENEMY', 1);
define('KILL_THE_BOSS', 5);
class Game
{
protected $score = 0;
public function addScore($score)
{
$this->score += $score;
}
public function getScore()
{
return $this->score;
}
}
$player = new Game();
$player->addScore(KILL_THE_ENEMY);
$player->addScore(KILL_THE_ENEMY);
$player->addScore(KILL_THE_BOSS);
var_dump($player->getScore());
// int(7)
Referências
- http://pt.slideshare.net/guilhermeblanco/php-para-adultos-clean-code-e-object-calisthenics
- http://williamdurand.fr/2013/06/03/object-calisthenics/
- http://www.maawko.com/blog/carreira/object-calisthenics-regras-pra-um-codigo-melhor/
- https://github.com/object-calisthenics/phpcs-calisthenics-rules
- https://www.youtube.com/watch?v=u-w4eULRrr0
Seu código reflete o profissional que você é, então, zele para que ele, assim como você, cresça e se desenvolva.
Obrigado!
@doriansneto
dorianneto.com.br