Hey dev, saiba como melhorar seu código, fuja dos code smells!
Tags: cleancode, programming, cleancoding, webdev
Published: 2023-08-24 21:50:58

Olá leitor, tudo bem?

Hoje vamos ver como podemos melhorar seu código com dicas simples, porém nem sempre acabamos vendo esses detalhes.

Vamos lá, começaremos com um simples código em PHP, que por sinal está bem ruim, iremos melhorar esse código no decorrer desse artigo, então bora lá.

Vamos começar pelo código em si, segue o ele:

```
class TotalSmell
{
    public function adminLoginSubmit(){

        if (!isset($_SESSION['admin'])) {

            if ($_SERVER['REQUEST_METHOD'] == 'POST') {

                if (isset($_POST['adminLogin']) || isset($_POST['adminPass'])) {

                    $a = (trim($_POST['adminLogin']));
                    $b = $_POST['adminPass'];

                $new = new AdminModel();
                $VALID = $new->validateLoginAdmin($a, $b);

                    if ($VALID) {

                            $_SESSION['admin']  = $valid->id_admin;
                            $_SESSION['user']   = $valid->usuario_admin;

                        header('location:http://localhost/public/admin/' . '?pagina=' . 'inicio');
                        return;

                    }

                    $_SESSION['error'] = 'Login Inválido';

                    header('location:http://localhost/public/admin/' . '?pagina=' . 'admin-login');
                    return;

                }

                $_SESSION['error'] = 'Login ou senha inválido, tente novamente';

                    header('location:http://localhost/public/admin/' . '?pagina=' . 'admin-login');
                return;
            }

        header('location:http://localhost/public/admin/' . '?pagina=' . 'inicio');
            return;
        }

        header('location:http://localhost/public/admin/' . '?pagina=' . 'inicio');
    }
}
```
Basicamente, esse código está validando o login de um usuário admin e salvando em sessão, sim, eu sei, o código está péssimo, mas essa é a intenção neste artigo.

> O que é $a? O que é $b? Para que tanta linha em branco? E essa indentação?ahhhhhhhh vou surtar com tanto code smells!!!!

Melhoraremos um pouco ele, vamos passar por algumas etapas e no final teremos um código bem melhor. Segue o rolo…

```
class RemovendoEspacosRenomeandoVariaveis
{
    public function adminLoginSubmit()
    {
        if (!isset($_SESSION['admin'])) {
            if ($_SERVER['REQUEST_METHOD'] == 'POST') {
                if (isset($_POST['adminLogin']) || isset($_POST['adminPass'])) {
                    $adminUser = (trim($_POST['adminLogin']));
                    $adminPass = $_POST['adminPass'];
                    $admin = new AdminModel();
                    $isValid = $admin->validateLoginAdmin($adminUser, $adminPass);
                    if ($isValid) {
                        $_SESSION['admin']  = $isValid->id_admin;
                        $_SESSION['user']   = $isValid->usuario_admin;
                        header('location:http://localhost/public/admin/' . '?pagina=' . 'inicio');
                        return;
                    }
                    $_SESSION['error'] = 'Login Inválido';
                    header('location:http://localhost/public/admin/' . '?pagina=' . 'admin-login');
                    return;
                }
                $_SESSION['error'] = 'Login ou senha inválido, tente novamente';
                header('location:http://localhost/public/admin/' . '?pagina=' . 'admin-login');
                return;
            }
            header('location:http://localhost/public/admin/' . '?pagina=' . 'inicio');
            return;
        }
        header('location:http://localhost/public/admin/' . '?pagina=' . 'inicio');
    }
}
```
Perceba que aqui, deixamos esse código um pouco mais limpo, removendo espaços desnecessários, renomeando variáveis e melhorando a indentação. Até aqui, nada de diferente, apenas organização.

Agora nessa próxima etapa, vamos tirar um pouco da complexidade do código:

```
class TirandoComplexidade
{
    public function adminLoginSubmit()
    {
        if (isset($_SESSION['admin'])) {
            header('location:http://localhost/public/admin/' . '?pagina=' . 'inicio');
        }
        if ($_SERVER['REQUEST_METHOD'] != 'POST') {
            header('location:http://localhost/public/admin/' . '?pagina=' . 'inicio');
            return;
        }
        if (!isset($_POST['adminLogin']) || !isset($_POST['adminPass'])) {
            $_SESSION['error'] = 'Login ou senha inválido, tente novamente';
            header('location:http://localhost/public/admin/' . '?pagina=' . 'admin-login');
            return;
        }
        $adminUser = (trim($_POST['adminLogin']));
        $adminPass = $_POST['adminPass'];
        $admin = new AdminModel();
        $isValid = $admin->validateLoginAdmin($adminUser, $adminPass);
        if (!$isValid) {
            $_SESSION['error'] = 'Login Inválido';
            header('location:http://localhost/public/admin/' . '?pagina=' . 'admin-login');
            return;
        }
        $_SESSION['admin']  = $isValid->id_admin;
        $_SESSION['user']   = $isValid->usuario_admin;
        header('location:http://localhost/public/admin/' . '?pagina=' . 'inicio');
    }
}
```
Perceba que sempre que levamos o código mais para a margem (esquerda), mais simples fica de se ler e menos complexo fica de se entender. Nesse exemplo, fica claro o conceito de inversão de condicional, onde invés de fazermos o if pela condição verdadeira, estamos fazendo pela condição falsa e caindo fora do método, deixando assim muito mais simples.

Exemplo fazendo a condicional em cima da condição verdadeira:
```
if ($variavel) {
  lógica...
  lógica...
  mais lógica...
  return $resultado;
}
return false;
```
Exemplo fazendo a condicional em cima da condição negativa:

```
if (!$variavel) {
  return false;  
}
lógica...
lógica...
mais lógica...
return $resultado;
```
Perceba que se $variavel for falso, nulo, ou não existir, retorna falso e acabou, se não, segue a vida. Claro, em um único if talvez não fique tão claro, mas voltando para o nosso exemplo de código do inicio, onde temos vários if’s um dentro do outro facilita, e muito.

Podemos melhorar ainda mais esse código do exemplo inicial, segue mais uma melhoria:
```
class Constants
{
    const START_URL = 'http://localhost/public/admin/?pagina=inicio';
    const LOGIN_URL = 'http://localhost/public/admin/?pagina=admin-login';
    const INVALID_LOGIN_MESSAGE = 'Login inválido';

    public function adminLoginSubmit()
    {
        if (isset($_SESSION['admin'])) {
            header('location:' . self::START_URL);
        }
        if ($_SERVER['REQUEST_METHOD'] != 'POST') {
            header('location:' . self::START_URL);
            return;
        }
        if (!isset($_POST['adminLogin']) || !isset($_POST['adminPass'])) {
            $_SESSION['error'] = self::INVALID_LOGIN_MESSAGE;
            header('location:' . self::LOGIN_URL);
            return;
        }
        $adminUser = (trim($_POST['adminLogin']));
        $adminPass = $_POST['adminPass'];
        $admin = new AdminModel();
        $isValid = $admin->validateLoginAdmin($adminUser, $adminPass);
        if (!$isValid) {
            $_SESSION['error'] = self::INVALID_LOGIN_MESSAGE;
            header('location:' . self::LOGIN_URL);
            return;
        }
        $_SESSION['admin']  = $isValid->id_admin;
        $_SESSION['user']   = $isValid->usuario_admin;
        header('location:' . self::START_URL);
    }
}
```
Nessa etapa a mudança não é tão grande quanto nossa última mudança, mas não deixa de ser importante, as constantes nos garantem a alteração fácil do código. Perceba que, se eu precisar mudar a url de redirecionamento e o código for para produção, será necessário mudar em diversos lugares, gerando um monte de dor de cabeça e um par de bug’s para resolver…

Vamos melhorar um pouco mais?

>Essa é a ultima desse artigo, eu prometo!

```
class SeparandoEmMetodos
{
    const START_URL = 'http://localhost/public/admin/?pagina=inicio';
    const LOGIN_URL = 'http://localhost/public/admin/?pagina=admin-login';
    const INVALID_LOGIN_MESSAGE = 'Login inválido';

    public function adminLoginSubmit():void
    {
        $this->isAdminLogged();
        $this->isPostMethod();
        $this->validatePost();
        $admin = new AdminModel();
        $user = $admin->validateLoginAdmin(trim($_POST['adminLogin']), $_POST['adminPass']);
        if (!$user) {
            $this->returnInvalidLogin();
        }
        $this->returnValidLogin($user);
    }

    public function isAdminLogged(): void
    {
        if (isset($_SESSION['admin'])) {
            $this->redirect(self::START_URL);
        }
    }

    public function isPostMethod(): void
    {
        if ($_SERVER['REQUEST_METHOD'] != 'POST') {
            $this->redirect(self::START_URL);
        }
    }

    public function validatePost(): void
    {
        if (!isset($_POST['adminLogin']) || !isset($_POST['adminPass'])) {
            $_SESSION['error'] = self::INVALID_LOGIN_MESSAGE;
            $this->redirect(self::LOGIN_URL);
        }
    }

    public function returnInvalidLogin(): void
    {
        $_SESSION['error'] = self::INVALID_LOGIN_MESSAGE;
        $this->redirect(self::LOGIN_URL);
    }

    public function returnValidLogin(stdClass $user): void
    {
        $_SESSION['admin'] = $user->id_admin;
        $_SESSION['user'] = $user->usuario_admin;
        $this->redirect(self::START_URL);
    }

    public function redirect(string $url): void
    {
        header('location:' . $url);
    }
}
```
Nesse ponto, não deixamos o código pequeno em quantidades de linhas, mas garantimos a reutilização de lógica sem duplicidade. Removemos as duplicidades para métodos, deixando assim mais fácil ainda de se dar manutenção nesse código.

Ficou bem mais simples, limpo e organizado em comparação ao primeiro exemplo. Perceba que a finalidade do código se manteve a mesma, a lógica principal não mudou, e isso é importante nessa refatoração.

Perceba também que os nomes dos métodos estão claros e que cada método está com pouca responsabilidade.

Métodos devem ter preferencialmente uma única responsabilidade, assim você garante a reutilização dos mesmos, facilita fazermos testes unitários, facilita a vida de quem vai fazer o code review e de quem vai dar manutenção nesse código no futuro.

Com essas dicas que passei aqui, espero que eu tenha conseguido te fazer entender como podemos evoluir nossos códigos. Demorei um tempo para entender esses conceitos, porém depois que entendi isso, meu código evoluiu bastante.

Espero ter ajudado, até mais ;)