Aplicações Laravel que gritam seu domínio
Tags: laravel, braziliandevs, php, cleancode
Published: 2023-12-20 15:29:43

Laravel rapidamente se tornou a estrela do desenvolvimento PHP, e temos Taylor Otwell para agradecer por isso. Não é apenas um framework; é quase uma varinha mágica para desenvolvedores PHP, transformando tarefas complexas em algo simples. Com seu _tool-kit_ completo, o Laravel revolucionou a maneira como pensamos o desenvolvimento em PHP, tornando-o mais acessível e prazeroso.

Mas aqui está uma consideração importante: às vezes, nossos queridos apps Laravel tendem a se parecer um pouco... uniformes. Não é um "erro" do Laravel, mas sim uma característica intrínseca a muitos frameworks fullstack ou REST que são ricos em funcionalidades. Eles oferecem tantas ferramentas e estruturas prontas que, sem um esforço consciente, podemos acabar com aplicações que, apesar de altamente funcionais, não se destacam em termos de personalidade única (Não gritam seu domínio).

## Domínios Gritantes

![Image Pessoa gritando](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mecmvaqowes63i9j9q1q.png)

Sabe como uma primeira impressão pode dizer muito? No mundo do desenvolvimento de software, isso é regra de ouro. E é aqui que a ideia dos "Domínios Gritantes" entra em cena, um conceito cunhado pelo famoso Uncle Bob como "Screaming Architecture". O truque é simples: só de dar uma olhada na estrutura de um software, você já capta a ideia geral do que ele se propõe a fazer. É como se o próprio código te desse as boas-vindas e te contasse sua história.

Aqui um simples exemplo: nosso domínio será uma empresa de logística. Antes de te da contexto gostaria apenas que olhasse para a estrutura de pastas desse modelo de negócio. Leia cuidadosamente cada nome de pasta e cada nome de classe (Lembrando arquitetura de software não é somente organização de arquivos)
**Importante: nome de arquivos estão em português para fins  de clareza na explicação, mas sempre escreva software em inglês.**

`app/
│
├── Models/
│   ├── Produto.php
│   ├── Armazem.php
│   ├── Transporte.php
│   └── Rastreio.php
|   |__ ProdutoTipo.php
|   |__ RastreioTipo.php
│
├── Repositories/
│   ├── ProdutoRepository.php
│   ├── ArmazemRepository.php
│   ├── TransporteRepository.php
│   └── RastreioRepository.php
│
├── Contracts/
│   ├── TransporteStrategyInterface.php
│   ├── RastreioStrategyInterface.php
│   ├── VeiculoInterface.php
│   └── RastreioInterface.php
│
├── Strategies/
│   ├── TransporteStrategy.php
│   ├── RastreioStrategy.php
│   ├── Transporte/
│   │   ├── NavioStrategy.php
│   │   ├── CaminhaoStrategy.php
│   │   └── AviaoStrategy.php
│   └── Rastreio/
│       ├── RastreioTempoRealStrategy.php
│       └── RastreioPadraoStrategy.php
│
├── Services/
│   ├── RastreioService.php
│   ├── TransporteService.php
│   ├── ArmazenamentoService.php
│   └── EntregaService.php
│
├── Controllers/
│   ├── ProdutoController.php
│   ├── TransporteController.php
│   ├── RastreioController.php
│   └── ArmazenamentoController.php
│
├── Factories/
│   ├── VeiculoFactory.php
│   └── RastreioFactory.php
│
└── Jobs/
    ├── AtualizarStatusEntrega.php
    ├── NotificarRastreioTempoReal.php
    └── ProcessarEntregaProduto.php`

### Entendo Domínio de logística
No nosso modelo de logística, lidamos principalmente com transporte, o que implica que estamos sempre movimentando algo – neste caso, produtos. No nosso modelo de negócio, oferecemos o rastreamento desses produtos, e o tipo de rastreamento varia conforme o veículo utilizado. Cada meio de transporte, seja por terra, mar ou ar, possui um sistema de rastreio adaptado às suas características e necessidades específicas.
 
No nosso projeto Laravel voltado para logística, cada elemento da arquitetura não apenas cumpre uma função específica, mas também ecoa fortemente o domínio a que pertence. Com a Separação de Preocupações (SoC) e injeções de dependência bem implementadas, criamos um sistema onde a função de cada parte é claramente definida, refletindo as complexidades do setor logístico. Os Models estabelecem a base, simbolizando entidades críticas como produtos e veículos. As Strategies de transporte e rastreio, adaptáveis através de injeções de dependência, mostram a flexibilidade necessária para o dinamismo do nosso negócio. Os Repositories se dedicam exclusivamente à interação com o banco de dados, mantendo essa lógica separada da camada de negócios.

Os Services lidam com a lógica de negócios, enquanto os Controllers fazem parte da camada de acesso, gerenciando a interação entre a lógica de negócios e as demais interfaces do sistema. Essa clara demarcação de responsabilidades não só atende às necessidades específicas da logística, mas também transmite com clareza o propósito do sistema. Cada componente do software se alinha perfeitamente a um aspecto específico do negócio, tornando a arquitetura intuitiva e eficaz. É uma representação fiel do domínio de logística, facilitando tanto o desenvolvimento quanto a operacionalização do sistema.

a nível de comparação, segue uma arquitetura simplista do que o laravel "impõe" para gerênciar esse domínio.
`app/
│
├── Http/
│   ├── Controllers/
│   │   ├── ProdutoController.php
│   │   ├── TransporteController.php
│   │   ├── RastreioController.php
│   │   └── ArmazenamentoController.php
│   │
│   ├── Middleware/
│   │   ├── AuthMiddleware.php
│   │   ├── LoggingMiddleware.php
│   │   └── ...
│   │
│   ├── Requests/
│   │   ├── ProdutoRequest.php
│   │   ├── TransporteRequest.php
│   │   ├── RastreioRequest.php
│   │   └── ArmazenamentoRequest.php
│   │
│   └── ...
│
├── Models/
│   ├── Produto.php
│   ├── Transporte.php
│   ├── Rastreio.php
│   └── ...
│
└── ...`

No caso acima, podemos notar uma arquitetura mais genérica, que pode atender ao domínio, mas ainda não temos uma noção clara do que essa transportadora faz em alguns aspectos.

### Documentação viva
A Screaming Architecture, quando aplicada ao nosso domínio de logística, tornou a estrutura do código uma documentação viva e clara. Por exemplo, se tivermos diferentes tipos de veículos de transporte, como navios, caminhões e aviões, cada um com suas estratégias de rastreamento distintas, a arquitetura do código refletirá essa complexidade de maneira evidente.

Imagine que ao navegar pelo código-fonte, um novo desenvolvedor pode identificar facilmente as pastas e classes relacionadas a cada tipo de veículo e suas estratégias de rastreamento. Isso não elimina a necessidade de documentação externa, mas torna essa documentação mais sobre o domínio do negócio em sí do que sobre o que cada parte do código faz, pois a própria estrutura do código comunica como a aplicação lida com esses aspectos do negócio.

Essa clareza arquitetural não apenas simplifica o processo de integração de novos membros da equipe, mas também torna mais eficaz o trabalho contínuo de desenvolvimento, manutenção e expansão da aplicação.

### Testabilidade

Quando a arquitetura "grita" o domínio, ela torna o teste de código mais simples e compreensível. Ainda no nosso contexto de logística e temos diferentes estratégias de rastreamento para navios, caminhões e aviões.

Com essa arquitetura clara, podemos facilmente criar testes para cada uma dessas estratégias. Por exemplo, podemos escrever um teste para garantir que a estratégia de rastreamento de navios funcione corretamente. Isso envolveria simular o comportamento de rastreamento de um navio em diferentes situações e verificar se os resultados estão corretos. Segue um exemplo abaixo:

```php

<?php
use PHPUnit\Framework\TestCase;
use GuzzleHttp\Client;
use GuzzleHttp\Handler\MockHandler;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Psr7\Response;

class NavioRastreioStrategyTest extends TestCase
{
    public function testDeveRetornarCidadeEstadoLink()
    {
        $mockResponse = new Response(200, [], json_encode([
            'latitude' => 42.12345,
            'longitude' => -71.98765,
        ]));
        $mock = new MockHandler([$mockResponse]);
        $handlerStack = HandlerStack::create($mock);
        $httpClient = new Client(['handler' => $handlerStack]);

        $navio = $this->getMockBuilder(Navio::class)
            ->disableOriginalConstructor()
            ->getMock();

        $navioMock->codigo = 'COD123';
        $navioMock->tipo_mercadoria = 'AD234BC';
        /**http client é um parametro opcional
        é setado automaticamente quando uam strategy é chamada
        mas para tornar a class testavel ele pode mockar essa cliente
        **/
        $strategy = new RastreioStrategy($httpClient);
        // Automaticamente chama NavioRastreioStrategy
        $result = $strategy->rastrear($navio);

        $data = json_decode($result, true);

        $this->assertEquals('Exemplo Cidade', $result->cidade->nome);
        $this->assertEquals('Exemplo Estado', $result->estado->nome);
        $this->assertEquals('https://maps.google.com/?q=42.12345,-71.98765', $result->googleMaps->link);
    }
}

```
Nesse teste conseguimos testar a regra de négocio, é claro é um teste bem feliz que falharia provavelmente, mas a ideia central é como nossa arquitetura que grita tornou nosso caso de um uso tão óbvio a nossa aplicação que foi muito facil criar um teste para esse nosso subdomínio que é rastrear navios. 


### Conclusão

Usar uma arquitetura que claramente comunica os problemas que o software busca resolver é uma vantagem significativa para sistemas que visam longevidade. Embora possa haver preocupações futuras com a descontinuação do Laravel, não estamos considerando essa variável, pois é improvável.

As vantagens dessa abordagem incluem:

- Documentação viva: A documentação do software se concentra no domínio do problema, tornando-a mais relevante e útil.
- Testabilidade: A implementação de testes, incluindo o desenvolvimento orientado a testes, permite que o software seja atualizado facilmente a cada nova versão estável do framework.
- Escalabilidade: Uma arquitetura gritante não apenas orienta os desenvolvedores sobre o que cada componente representa, mas também implicitamente indica como as coisas devem ser implementadas no futuro, facilitando a escalabilidade à medida que novos recursos são adicionados ao sistema.


> Por fim: faça seu código ter personalidade