Além do código limpo (clean code) — sacadas para escrever códigos simples

Se você trabalha com criação de software ou com gestão de equipes de desenvolvimento, você sabe do que estou falando. O cliente de software é um ser humano normal investido de uma capacidade estranha de pedir coisas complexas.
Por vezes, recebemos a missão de desenvolver um produto cujas regras de negócio são um emaranhado obscuro de caminhos ambíguos. Quantas vezes esses desafios já te custaram horas de trabalho e a sensação de que não será possível concluir com êxito.
Mas depois de dizer sim a muitos desafios que eu, no meu íntimo, titubeava comigo mesmo “você está louco? Isso não dá pra ser feito!”, conclui que você pega o jeito e aprende alguns princípios.
Quero compartilhar aqui alguns princípios que aprendi para criação de classes.
Primeiro escreva o roteiro
Quando for criar uma classe, SEMPRE utilize o padrão de projeto FACHADA ( https://code.tutsplus.com/pt/tutorials/design-patterns-the-facade-pattern--cms-22238).
A atividade se torna muito mais simples quando você deixa claro todos os procedimentos necessários que serão realizados antes de começar a codificar.
Por exemplo, imagine que você irá escrever uma classe para cadastrar uma nova pessoa. Em vez de sair codificando, escreva primeiro o roteiro de execução dessa tarefa. Veja como fica mais simples implementar e manter:
<?phpnamespace App\Domain\Pessoas\Cadastrar;/**
* Classe para cadastro de uma pessoa.
*/
class Feature
{
/**
* Implementa a funcionalidade.
*/
public function execute()
{
$this->validarDados();
$this->checarSeEmailJaCadastrado();
$this->cadastrarPessoa();
$this->enviarEmailConfirmacao();
return [ 'pessoa' => $this->pessoa->values() ];
} /**
* Valida os dados informados no formulário.
*/
protected function validarDados()
{
} /**
* Checa se já existe uma pessoa cadastrada com o e-mail.
*/
protected function checarSeEmailJaCadastrado()
{
} /**
* Efetiva o cadastro da pessoa
*/
protected function cadastrarPessoa()
{
} /**
* Envia e-mail de confirmação para a caixa de e-mail da pessoa.
*/
protected function enviarEmailConfirmacao()
{
}
/**
* Valida os dados informados no formulário.
*/
protected function validarDados()
{
}
}
Expressões condicionais dentro de variáveis
Não precisamos ficar lendo todo o código para entender como ele funciona ou ficar poluindo com comentários para explicar expressões condicionais complexas. Podemos criar variáveis para facilitar essa atividade.
Veja o exemplo abaixo:
<?phpnamespace App\Domain\Conta;/**
* Classe para cadastro de uma pessoa.
*/
class ContaCorrente extends ContaBancaria
{
/**
* Implementa a funcionalidade de sacar dinheiro no caixa eletrônico.
*/
public function sacar( $valor )
{
$saldo_conta = $this->consultarSaldoConta();
$limite_saque = $this->valorDisponivelSaque();
$saldo_maquina = $this->consultarSaldoMaquina();
$saldo_suficiente = $saldo >= $valor;
$limite_saque_diario = $limite_saque >= $valor;
$maquina_possui_valor = $this->valorDisponivelMaquina() >= $valor; if ( !$saldo_suficiente )
{
$msg = "Seu saldo é insuficiente. Valor solicitado: {$valor}. Saldo: {$saldo}.";
throw new \Exception( $msg );
} if ( !$limite_saque_diario )
{
$msg = "O valor solicitado ultrapassa o limite disponível para saque diário: {$limite_saque}.";
throw new \Exception( $msg );
} if ( !$maquina_possui_valor )
{
$msg = "Desculpe, mas a maquina não possui o valor suficiente para realizar o saque.";
throw new \Exception( $msg );
} return $this->efetivarSaque();
}
}
Expressões if/switch x arrays
Podemos simplificar bastante nossos códigos reduzindo o uso de expressões if/case sequencias quando os valores a serem comparados são fixos e pré-conhecidos.
Veja uma função escrita com IFs:
<?phpfunction validarCategoria( $categoria ) {
if ( $categoria == 'pessoal' ) {
return 'Pessoal';
} if ( $categoria == 'profissional' ) {
return 'profissional';
} if ( $categoria == 'hoobies' ) {
return 'Hobbies';
} if ( $categoria == 'financas' ) {
return 'Finanças';
} if ( $categoria == 'outras' ) {
return 'Outras categorias';
} return null;
}
Agora a mesma função utilizando switch:
<?phpfunction validarCategoria( $categoria ) {
switch ( $categoria ) {
case 'pessoal':
return 'Pessoal'; case 'profissional':
return 'profissional'; case 'hoobies':
return 'Hobbies'; case 'financas':
return 'Finanças'; case 'outras':
return 'Outras categorias'; default:
return null;
}
}
Nos dois casos acima, percebe-se que a manutenção do código será cansativa, tendo que navegar em linhas intercaladas. Agora, veja o mesmo código escrito com arrays:
<?phpfunction validarCategoria( $categoria ) {
$categorias = [
'pessoal' => 'Pessoal',
'profissional' => 'Profissional',
'hoobies' => 'Hobbies',
'financas' => 'Finanças',
'outras' => 'Outras categorias',
]; return $categorias[ $categoria ] ?? null;
}
Evitar chamadas recursivas
Uma classe com chamadas recursivas te obriga a ler todo o código para você entender o funcionamento. E, se você não tiver a sacada de desenhar um fluxograma logo no início, pode acabar perdendo tempo lendo o mesmo código várias vezes para se memorizar com seu fluxo.
Veja como na classe abaixo você é obrigado a navegar até a última linha para saber o que está acontecendo.
<?phpnamespace App\Domain\SupermercadoX;/**
* Classe para adicionar um produto nas compras de um cliente.
*/
class Caixa
{
/**
* Implementa a funcionalidade.
*/
public function cadastrar()
{
$this->procedimentoA();
$this->procedimentoB();
$this->procedimentoC();
} /**
* Implementa a funcionalidade.
*/
public function procedimentoA()
{
// Algum codigo
$this->procedimentoA1();
$this->procedimentoA2();
$this->procedimentoA3();
} /**
* Implementa a funcionalidade.
*/
public function procedimentoA1()
{
// Algum código
} /**
* Implementa a funcionalidade.
*/
public function procedimentoA2()
{
// Algum código
} /**
* Implementa a funcionalidade.
*/
public function procedimentoB()
{
// Algum código
$this->procedimentoC();
} /**
* Implementa a funcionalidade.
*/
public function procedimentoC()
{
// Algum código
$this->procedimentoD();
} /**
* Implementa a funcionalidade.
*/
public function procedimentoD()
{
// Algum código
}
}
Agora perceba a diferença, quando você não possui chamadas recursivas:
<?phpnamespace App\Domain\SupermercadoX;/**
* Classe para adicionar um produto nas compras de um cliente.
*/
class Caixa
{
/**
* Implementa a funcionalidade.
*/
public function cadastrar()
{
$this->procedimentoA();
$this->procedimentoA1();
$this->procedimentoA2();
$this->procedimentoA3();
$this->procedimentoB();
$this->procedimentoC();
$this->procedimentoD();
} /**
* Implementa a funcionalidade.
*/
public function procedimentoA()
{
// Algum código
} /**
* Implementa a funcionalidade.
*/
public function procedimentoA1()
{
// Algum código
} /**
* Implementa a funcionalidade.
*/
public function procedimentoA2()
{
// Algum código
} /**
* Implementa a funcionalidade.
*/
public function procedimentoB()
{
// Algum código
} /**
* Implementa a funcionalidade.
*/
public function procedimentoC()
{
// Algum código
} /**
* Implementa a funcionalidade.
*/
public function procedimentoD()
{
// Algum código
}
}
Cada regra de negócio em uma classe separada
Quando escrevemos uma classe, pensamos que todas as classes devem ter mais de um método para justificar sua existência; assim, algumas classes ficam muito extensas e devem ser lidas obrigatoriamente para verificar se todas as regras de negócio foram implementadas.
<?phpnamespace App\Domain\EmprestimoFinanciamentos;/**
* Classe para adicionar um produto nas compras de um cliente.
*/
class Emprestimo
{
/**
* Implementa a funcionalidade.
*/
public function conceder()
{
$this->avaliarHistoricoCliente();
$this->avaliarPatrimonioAtualCliente();
$this->prospectarCapacidadeClientePagarEmprestimo();
$this->executarProcedimento1();
$this->executarProcedimento2();
$this->executarProcedimento3();
$this->concluirOperacao();
}
}
Uma sacada simples para deixar a classe principal mais simples e as regras de negócio mais fácil de serem encontradas (inclusive ver se já foram implementadas), é criar uma classe específica para cada regra de negócio, deixando na classe apenas os métodos da implementação técnica do código.
Veja como ficaria seu a árvore de arquivos do seu projeto:

E sua classe mais limpa:
<?phpnamespace App\Domain\EmprestimoFinanciamentos;/**
* Classe para adicionar um produto nas compras de um cliente.
*/
class Emprestimo
{
/**
* Implementa a funcionalidade.
*/
public function conceder()
{
$this->avaliarHistoricoCliente();
$this->avaliarPatrimonioAtualCliente();
$this->prospectarCapacidadeClientePagarEmprestimo();
$this->executarProcedimento1();
$this->executarProcedimento2();
$this->executarProcedimento3();
$this->concluirOperacao();
}
}
Conclusão
O clean code não precisa acabar onde os livros terminam. Experimente você mesmo fazer suas descobertas e construir códigos cada vez mais simples.
