Laravel #4: Boas praticas #1

Laravel - Boas Praticas | Parte 1

Como em qualquer trabalho realizado, existe uma lista de boas praticas que devem ser seguidas. Neste caso, vamos falar sobre essas boas praticas usando a framework Laravel.

Em muitos projectos, ou quase todos, estas boas praticas são sempre deixadas para segundo plano, causando em muitos casos constrangimentos a médio ou longo prazo.

Algumas empresas adoptam as boas praticas da comunidade, mas outras tantas adoptam as suas próprias boas praticas, criando documentações próprias para que seus programadores sigam essas linhas de implementação.

Este assunto vai ser dividido em dois artigos, pois o conteúdo é bastante extenso, deixando aqui apenas os que considero mais críticos e quem devem ser sempre mantidos, independente do tipo de projecto

Modelos grandes e controladores pequenos

O que muitas vezes assistimos, é que muitas das validações necessárias aos projectos ficam dentro dos controladores, tornando-os gigantes, dependendo do projecto e das regras de negocio.

Uma consideração que deve ser mantida, é que todas as validações que estejam relacionadas a dados que vêm da base de dados, devem ser mantidas nos modelos.

Em casos de actividades mais densas, podemos dividir algumas coisas que normalmente são deixadas dentro do modelo, em repositórios, como é o caso de Query Builders e consultas SQL.

Outro caso que podemos ter consideração, é quando existe a possibilidade de ter vários parâmetros para uma consulta a base de dados, podendo criar padrões de consulta nos repositórios.

Exemplo de controlador:

public function index()
{
    return view('index', ['clients' => $this->client->getWithNewOrders()]);
}

Exemplo de modelo:

class Client extends Model
{
    public function getWithNewOrders()
    {
        return $this->verified()
            ->with(['orders' => function ($q) {
                $q->where('created_at', '>', Carbon::today()->subWeek());
            }])
            ->get();
    }
}

Regra de negócio separadas

Todos os projectos têm as suas regras de negocio. O que normalmente vemos, é ser adicionada essas regras nos controladores ou modelos. As regras do negocio devem ser separadas em classes que tenham apenas essa responsabilidade, receber e validar determinados dados.

Usando uma validação separada, é muitos mais fácil de manter o código e validar possíveis problemas nessas mesmas validações do negocio.

Exemplo de controlador:

public function store(Request $request)
{
    $this->userService->handleUploadedImage($request->file('image'));

    ....
}

Exemplo de classe:

class UserService
{
    public function handleUploadedImage($image)
    {
        if (!is_null($image)) {
            $image->move(public_path('images') . 'temp');
        }
    }
}

DRY – Não se repita

Em muitos casos, principalmente no caso de projectos densos e mantidos por vários programadores, existe a tendência de replicar código, sem que seja mesmo necessário. Sempre que se verificar que existe pedaços de código que podem ser usados em várias partes do projecto, mais que uma vez, devem ser colocados separadamente de forma a ser reutilizado as vezes necessárias.

Por exemplo, podemos colocar esse código dentro de uma classe que terá várias funções que podem ser reutilizadas por todo o projecto.

Vejamos o seguinte exemplo abaixo:

foreach (User::all() as $user) {
}

Podemos ver que a cada reentrada no foreach, o modelo User é chamado, e irá sempre retornar todos os utilizadores da base de dados. Isto também é válida para as Blades e consulta a serviços externos.

Sempre que precisares de executar algo do género, usa o modelo para recolher os dados que precisas para dentro de uma variável, e só depois fazer a iteração.

$users = User::all();

foreach ($users as $user) {
}

Comentários e nomes de variáveis claros

Este tópico abrange toda a programação e não apenas o Laravel. Comentar código com uma linguagem assertiva, nada demasiado extenso, é uma boa forma de ajudar quem está a ler o código pela primeira vez, ou mesmo para quem escreveu o comentário relembras aquilo que estava feito.

Esta prática é muitas vezes esquecida e deixa margem para alguns erros.

O nome das variáveis também é algo que deve ser levado em conta, pois deixar variáveis como $x ou $a, não ajuda durante a leitura do código. Por isso, manter as variáveis com nomes que sejam ilustrativos da sua real função, podem ser uma mais valia ao longo do tempo.

Constantes e ficheiros de idioma e configuração

Deixar texto escrito pelo código, especialmente quando este se pode repetir é péssimo. Imaginem o seguinte: estão a colocar numa variável o texto “Olá mundo”, e este procedimento é repetido várias vezes ao longo do código, onde o valor “Olá mundo” é adicionado em mais locais. Por sua vez, o negócio/cliente pede para que seja alterado o “Olá mundo” para outro valor qualquer. Usando uma constante, não teríamos de ir ao código, todas as vezes que encontrarmos o valor, e alterar o mesmo, bastando apenas utilizar o exemplo abaixo:

<?php

...

const HELLO_WORLD = "Olá Mundo";

...

public function helloWorld()
{
    return $article->type === self::HELLO_WORLD;
}

return back()->with('message', __('app.article_added'));

Também devemos ter em consideração deixar a nossa configuração em ficheiros como o .env, que pode ser acedido em qualquer parte do projecto, ou criar um ficheiro de configuração, que também pode ser acedido em qualquer parte do código, em vez ficar espalhada toda a configuração pelo projecto, podendo causar problemas a quando a necessidade de alterar a mesma configuração em todo o projecto.

Utilizar também ficheiros de idioma é o melhor caminho, especialmente quando trabalhamos com projectos que têm idiomas diferente. Mas não só isso, todas as mensagens ficam concentradas no mesmo ficheiro, sendo mais fácil de manter e alterar. O mesmo pode ser considerado para as configurações.

Não utilizar o ficheiro env para aceder a configuração

Tal como abordei acima, podemos aceder ao .env para recolher os dados por lá, mas não é aconselhável. Deve ser sempre criado um ficheiro de configuração onde fica toda a informação necessária para o bom funcionamento de todo o projecto.

Sendo assim, devemos alterar isto:

$apiKey = env('API_KEY');

E ter mais foco na utilização de:

// config/api.php
'key' => env('API_KEY'),

// Use data
$apiKey = config('api.key');

Conclusão

Estas e outras praticas que falarei no próximo artigo sobre o tema, devem ser sempre tidas em conta ao iniciar um projecto.

É também aconselhável, que estas praticas seja usadas desde o inicio do mesmo, para não causar um “refector” maior ao longo do tempo.