Três conceitos para um Código Limpo

Daniel Reis - Nov 17 '21 - - Dev Community

Prólogo

A pergunta mais constante entre os desenvolvedores que estão querendo sair do nível Júnior para Pleno é "será que meu código tá uma merda?" ou "beleza isso funciona, mas como melhorar esse lixo?" e se questionar sobre a qualidade do produto que você está entregando é um sinal de que você está (digi)evoluindo.

Na minha jornada como desenvolvedor eu venho cada vez entendendo que no final das contas o importante é a engenharia e não a ferramenta, até porquê você sabe que um CRUD é uma sequencia X que pode ser replicada em TODAS as linguagens, certo? Logo, se você sabe a teoria/engenharia, a pratica só precisa da ferramenta/linguagem.

Agora, vamos entender sobre conceitos/padrões que podem estar ligados diretamente à qualidade do código entregue, onde nós deveriamos nos preocupar muito mais do que sobre "qual framework usar".

O que vamos aprender?

Nesse post, quero dar exemplos de conceitos e métodologias para que possamos melhorar nosso código. Sendo eles:

  • DRY (Don't Repeat Yourself)
  • Early Return (Anti Hadouken)
  • KISS (Keep it Simple Stupid)

1. Dont Repeat Yourself (DRY)

O tal do DRY é algo bem visto quando o assunto é abstração. A ideia do principio é você não repetir coisas que podem ser abstraidas pra blocos de códigos únicos. Se você está fazendo o mesmo bloco de código duas vezes, ele é refatorável pra uma função com argumentos.

Não entendeu? Se liga aqui então:

class UserRepository {

    public function createUser(array $payload): bool
    {
        $query = $this->pdo->prepare('SELECT * FROM users WHERE email = :email');
        $query->bindParam(':email', $payload['email'], PDO::PARAM_STR);
        $query->execute();

        if ($query->count()) {
            throw new Exception('E-mail já cadastrado');
        }

        $query = $query->prepare('INSERT INTO users values (null,:name,:email, :password)');

        return $query->execute();
    }

    public function getUser(string $email): ?array
    {
        $query = $this->pdo->prepare('SELECT * FROM users WHERE email = :email');
        $query->bindParam(':email', $email, PDO::PARAM_STR);
        $query->execute();

        if (!$query->count()) {
            throw new Exception('Usuário inexistente.');
        }

        return $query->fetch(PDO::FETCH_ASSOC);
    }

}

Enter fullscreen mode Exit fullscreen mode

Nesse exemplo feito em menos de 5 minutos podemos ver que há uma duplicidade de código quando fazemos a query do createUser e a query do getUser e não há necessidade de duplicar isso caso haja uma função pra lidar com esse comportamento.

Se liga:

class UserRepository {

    public function createUser(array $payload): bool
    {
        $query = $this->getUserByEmail($payload['email']);

        if (count($query)) {
            throw new Exception('E-mail já cadastrado');
        }

        $query = $query->prepare('INSERT INTO users values (null,:name,:email, :password)');

        return $query->execute();
    }

    public function getUser(string $email): ?array
    {
        $query = $this->getUserByEmail($email);

        if (! count($query)) {
            throw new Exception('Usuário inexistente.');
        }

        return $query->fetch(PDO::FETCH_ASSOC);
    }

    public function getUserByEmail(string $email): array
    {
        $query = $this->pdo->prepare('SELECT * FROM users WHERE email = :email');
        $query->bindParam(':email', $email, PDO::PARAM_STR);
        $query->execute();

        return $query->fetch(PDO::FETCH_ASSOC);
    }

}

Enter fullscreen mode Exit fullscreen mode

Isolamos uma abstração em uma única função e usamos ela em 2 lugares e o código ainda ficou um pouco mais legível (desde que você dê um nome bacana pra sua função abstraida). Bacana né? Se a galera juninha prestasse atenção nesse tipo de coisa desde o dia zero já teriamos carros voadores :p

2. Early Return Statement

Beleza, agora vamos falar de complexidade de código: tá ligado aquele código que tem um monte de if/else um dentro do outro parecendo um hadouken? Então, isso ai é um PORRE pra gente que vai dar manutenção no futuro e muitas vezes perdemos uns minutos refatorando o negócio. Então, se ensinarmos a rapaziada como não criar esse tipo de código vai ser a maior vitória pros devs que mexem com legado (eu incluso).

Você não sabe o que é um código hadouken? É isso aqui ó:


class AuthRepository
{
    public function adminAuthenticate(array $credentials): bool
    {
        if ($user = User::where('email', $credentials['email'])) {
            $password = Hash::verify($user->password, $credentials['password']);
            if($password) {
                if ($user->isAdmin) {
                    Auth::login($user);
                    return true;
                }else {
                    throw new UnauthorizedException('vc n é um admin seu merda');
                }
            } else {
                throw new UnauthorizedException('senha errada seu otário');
            }
        } else {
            throw new UnauthorizedException('ce nem existe no meu banco wtf');
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Acho que nesse exemplo deu pra entender o conceito de hadouken, né? Encadeamos tantos ifs e elses que não fez o menor sentido e só aumentou a complexidade do código. Agora, se entendermos a lógica do Early Return a coisa fica um pouco mais bonita.

O que é: fazer com que o else seja sempre a condição principal e dar o retorno da função o quanto antes. Ou seja: negar a função e retornar em caso de erro. Não entendeu? Vamos pra prática então:


class AuthRepository
{
    public function adminAuthenticate(array $credentials): bool
    {
        $user = User::where('email', $credentials['email'])
        if (!$user) {
            throw new UnauthorizedException('ce nem existe no meu banco wtf');
        }

        $password = Hash::verify($user->password, $credentials['password']);
        if (!$password) {
            throw new UnauthorizedException('senha errada seu otário');
        }

        if (!$user->isAdmin) {
            throw new UnauthorizedException('vc n é um admin seu merda');
        }

        Auth::login($user);
        return true;
    }
}
Enter fullscreen mode Exit fullscreen mode

Negamos todas as condicionais pra fazer com que elas retornassem o quanto antes e garantimos uma melhor legibilidade pro código. O Early Return vem sendo cada vez mais citados por devs e empresas como algo obrigatório pra criar um código bacana e saber isso com certeza vai te deixar a frente de uma galera.

Mas Daniel, não devo usar o else? Bom, isso fica inteiramente pra você. Eu não gosto, mas tem vezes que não dá pra fugir. Fica ai a reflexão :p

3. Keep it Simple Stupid (KISS)

Cara, é bem legal implementar lógicas ao seu software e tudo mais porém chega numa hora que a própria linguagem já tem aquele método ali que você fez pronto, e com toda certeza mais otimizado. Então, pra quê?! As vezes manter as coisas simples são mais vantajosas a longo prazo e isso visto de um lado mais dev da vida onde temos gambiarras pra todo lado, é um puta ponto positivo.

Vamos um exemplo de um bloco de código zoado e uma versão desse mesmo bloco porém simples:

// Jeito zoado
function getOAuthProvider(string $providerId) {
    switch($providerId) {
        case 0:
            return 'twitch';
        case 1:
            return 'discord';
        case 2:
            return 'twitter';
        case 3: 
            return 'google';
        case 4: 
            return 'facebook';
    }
}

// Jeito simples
function getOAuthProvider(string $providerId) {
    $providers = ['twitch', 'discord', 'twitter', 'google', 'facebook'];
    return $providers[$providerId];
}

Enter fullscreen mode Exit fullscreen mode

Adicionar um switch case num bloco de código que era só retornar um array não parece engenharia demais? Sempre que você ver algo extremamente complexo, ou ficando grande, tente refatorar pra ficar o mais simples possível.

Gostou desse post? Clica no coraçãozinho e me siga nas redes sociais!

. . . . . . . . . . . . . . . . . . . .