Object Calisthenics em PHP – Parte 1

O conceito de object calisthenic foi criado pelo desenvolvedor Jeff Bay, que teve a visão de que praticar código reutilizável, limpo e de boa leitura é uma prática que necessita de muito exercício, ou seja, muita prática e constante melhoria e evolução através de ações e práticas.

Ele é composto por nove exercícios que constituem a aplicação dos mesmos ao se escrever código em orientação a objetos.

Object vem da programação orientada a objetos, e calisthenics do termo grego, Kales, simplificando, seria a forma de se obter um físico ou, no caso, um resultado a partir da prática de exercícios que deixarão seu código em “forma”.

Ao todo são nove regras básicas, veja abaixo:

  1. Um nível de indentação por método;
  2. Não use ELSE;
  3. Envolva seus tipos primitivos;
  4. Envolva suas collections em classes;
  5. Uma chamada de método por linha;
  6. Não abrevie;
  7. Mantenha as classes pequenas;
  8. Não tenha classes com mais de duas variáveis de instancia;
  9. Sem getters e setters;

Veremos neste artigo as duas primeiras que são exercícios fortíssimos que fazem já muita diferença quando praticados.

PHP Intermediário
Curso de PHP Intermediário
CONHEÇA O CURSO

1. Um nível de indentação por método

Como já especificado devemos internamente dentro de uma função usar somente um nível de indentação, quanto mais níveis de comandos de decisão ou estruturas de decisão, mais complexo o método fica, minando com a simplicidade do projeto.

Abaixo podemos ver um exemplo disso:

Código sem a regra de indentação:

class Customer
{
    public function getPromoCode(string $promoName)
    {
        // 1.
        if ($this->promoCode) {
            // 2.
            if (false === $this->promoCodeExpired()) {
                // 3.
                if ($this->promoName == $promoname) {
                    return $this->promoCode;
                } else {
                    throw new Exception('Promoção não existe mais');
                }
            } else {
                throw new Exception('Promoção Expirada');
            }      
        } else {
            throw new Exception('Cliente sem código de promoção');
        }
    }
}

Uma forma de “treinar” esse exercício é criando métodos protegidos auxiliares que tenham um motivo e reaproveitamento, atuando na facilitação da escrita e colocando os blocos dentro das funções de apoio.

Veja como resolvemos o problema acima:

class Customer
{
    public function getPromoCode(string $promoName)
    {
        if ($this->promoCode) {
            return $this->getValidPromoCode($promoName);
        } else {
            throw new Exception('Cliente sem código de promoção');
        }
    }

    protected function getValidPromoCode(string $promoName)
    {
        if (false === $this->promoCodeExpired()) {
            return $this->getPromoExists($promoName);
        } else {
            throw new Exception('Promoção Expirada');
        }    
    }

    protected function getPromoExists(string $promoName)
    {
        if ($this->promoName == $promoName) {
            return $this->promoCode;
        } else {
            throw new Exception('Promoção não existe mais');
        }
    }
}

2. Não use ELSE

Essa regra parece ser muito estranha, mas ela funciona muito bem com o conceito early return, que emprega o uso do “retorne seu valor o quanto antes”, ação que só é facilmente implementada dentro de funções, métodos ou loops.

A base deste exercício é sempre trabalhar com o return (ou continue), sabemos que ao cair em um return/continue o código abaixo não será executado o que ajuda na remoção dos “elses” ao inverter ou até modificar a validação antes usada.

Abaixo o código anterior com early return:

class Customer
{
    public function getPromoCode(string $promoName)
    {
        if ($this->promoCode) {
            return $this->getValidPromoCode($promoName);
        } 
        throw new Exception('Cliente sem código de promoção');
    }

    public function getValidPromoCode(string $promoName)
    {
        if (false === $this->promoCodeExpired()) {
            return $this->getPromoExists($promoName);
        }
        throw new Exception('Promoção Expirada'); 
    }

    public function getPromoExists(string $promoName)
    {
        if ($this->promoName == $promoName) {
            return $this->promoCode;
        }
        throw new Exception('Promoção não existe mais');
    }
}

Como trocamos os comandos de decisões para que fique um código limpo removemos os “else’s”, e simplificamos a lógica que passa a ser melhor compreendida e limpa, esse conceito também pode ser aplicador para loops, onde o intuito é usar o continue no lugar do “else”.

Vejamos abaixo um exemplo:

Antes:

// Exibir a lista de membros
// que pagaram a mensalidade
foreach ($members as $member) {
    if ($member->paid()) {
        $report[] = [$member->name => 'Paid'];
    } else {
        $report[] = [$member->name => 'Not Paid'];
    }
}

Depois:

// Sem Else
foreach ($members as $member) {
    if ($member->paid()) {
        $report[] = [$member->name => 'Paid'];
        continue;
    }
    $report[] = [$member->name => 'Not Paid'];
}

Ou até com um pouco mais de limpeza:

// Um pouco mais de limpeza
foreach ($members as $member) {
    $report[] = $member->paid() ? 
                    [$member->name => 'Paid'] : 
                    [$member->name => 'Not Paid'];
}

Conclusão

Veremos em breve as outras regras numa série de posts. O uso do object calisthenics trás muitos benefícios que em grande escala fazem uma grande diferença, comece esses exercícios e terá seu código elogiado e muito mais elegante.

Obviamente nem sempre é possível de imediato “atacar” seu código com os calisthenics, mas com refatorações isso começa a ficar natural e quanto mais prática mais natural fica a aplicação desses exercícios.

Espero que tenham gostado e nos vemos nos próximos posts. Bons estudos!

PHP Avançado
Curso de PHP Avançado
CONHEÇA O CURSO
Deixe seu comentário