PHP além do CRUD: como escrever código que não vira problema em produção

A maioria dos desenvolvedores PHP sabe fazer CRUD.
Isso não te torna pleno. Muito menos sênior.

O que diferencia um dev mais experiente não é o que ele sabe fazer, mas o que ele evita fazer.

Vou te ensinar aqui um padrão prático, usado em projetos reais, que resolve três problemas clássicos:

  • Controllers inchados
  • Regras de negócio espalhadas
  • Código impossível de testar ou evoluir

public function store(Request $request)
{
if (!$request->email) {
return response()->json([‘error’ => ‘Email obrigatório’], 422);
}

$user = User::create([
    'name' => $request->name,
    'email' => $request->email,
]);

Mail::to($user->email)->send(new WelcomeMail($user));

Log::info('Usuário criado', ['id' => $user->id]);

return response()->json($user);

}

Funciona? Funciona.

É bom? Não.

Por quê?

  • Controller decide regra de negócio
  • Controller cria usuário
  • Controller dispara e-mail
  • Controller registra log

Isso acopla tudo.

Pensamento pleno/sênior: separar responsabilidade

Controller não decide regra.
Controller orquestra.

Vamos refatorar com um Service + DTO, padrão simples e poderoso.


Criando um DTO (Data Transfer Object)

Isso evita Request sendo usado como regra de negócio.

final class CreateUserDTO
{
    public function __construct(
        public readonly string $name,
        public readonly string $email,
    ) {}
}

Simples, explícito e tipado.


Criando o Service (onde a regra mora)

final class CreateUserService
{
    public function execute(CreateUserDTO $dto): User
    {
        if (!filter_var($dto->email, FILTER_VALIDATE_EMAIL)) {
            throw new InvalidArgumentException('Email inválido');
        }

        $user = User::create([
            'name' => $dto->name,
            'email' => $dto->email,
        ]);

        Mail::to($user->email)->send(new WelcomeMail($user));

        Log::info('Usuário criado', ['id' => $user->id]);

        return $user;
    }
}

Agora sim:

  • Regra centralizada
  • Código reutilizável
  • Fácil de testar
  • Fácil de evoluir

Controller limpo (como deveria ser)

public function store(Request $request, CreateUserService $service)
{
    $dto = new CreateUserDTO(
        name: $request->name,
        email: $request->email
    );

    $user = $service->execute($dto);

    return response()->json($user);
}

O controller:

  • Recebe request
  • Constrói DTO
  • Chama serviço
  • Retorna resposta

Nada além disso.


O ganho real (que júnior não enxerga)

Testabilidade

Agora você testa a regra sem framework:

public function test_user_creation()
{
    $service = new CreateUserService();

    $dto = new CreateUserDTO(
        name: 'Leo',
        email: 'leo@email.com'
    );

    $user = $service->execute($dto);

    $this->assertEquals('Leo', $user->name);
}

Sem Request.
Sem Controller.
Sem gambiarra.


Evolução sem dor

Amanhã você precisa:

  • Enviar evento para fila
  • Criar usuário em sistema externo
  • Validar regra nova

Você altera um lugar só.


Mentalidade sênior (isso vale ouro)

” Código que funciona não é código bom.mCódigo bom é o que aguenta mudança.”

Pleno/sênior pensa assim:

  • Onde essa regra deve morar?
  • O que vai mudar daqui 6 meses?
  • Quem vai dar manutenção nisso?

Erros clássicos que isso evita

  • Fat models
  • Controllers gigantes
  • Services que viram controllers
  • Regra duplicada
  • Código impossível de refatorar

Esse tipo de abordagem não aparece em tutorial de YouTube, mas é exatamente o que mantém sistemas vivos em produção.

Leonardo

Engenheiro de Software especializado em PHP e Laravel, com ampla experiência no desenvolvimento de APIs, automações, sistemas de mensageria, estratégias de cache e integrações com serviços externos. Atua na arquitetura e evolução de sistemas escaláveis, com foco em performance, segurança, estabilidade e manutenibilidade do código, aplicando boas práticas de engenharia de software em ambientes de produção críticos.

Recent Posts

Como identificar um projeto WordPress mal feito em 10 minutos

Você não precisa ser especialista nem passar horas auditando código para saber se um projeto…

1 dia ago

WordPress não é amador. Amador é o uso que fazem dele.

WordPress não é lento, frágil ou amador. Ele só ficou mal-falado porque virou refém de…

2 dias ago

10 inteligências artificiais que você não pode ignorar em 2026

De assistentes que escrevem códigos a geradores de vídeos e músicas em segundos, essas inteligências…

3 dias ago

Como monitorar aplicação e servidor pelo WhatsApp (logs, erros e alertas)

WhatsApp é um canal excelente para alerta porque ele tem uma característica que e-mail e…

4 dias ago

AMP: o que é, para que serve, ainda vale a pena usar?

Durante alguns anos, o AMP foi tratado como solução quase obrigatória para quem queria desempenho…

4 dias ago

O que é Lighthouse e como usar para melhorar seu site

Performance, acessibilidade e boas práticas deixaram de ser “detalhes técnicos” e passaram a impactar diretamente…

5 dias ago