Estruturando o Projeto

O Lino foi desenvolvido para simplificar a criação de projetos escaláveis e modulares de maneira eficiente. Ele oferece uma solução bem estruturada, com uma separação clara de responsabilidades entre as camadas, e está preparado para crescer conforme as necessidades do seu projeto evoluem.


Ao criar um projeto com o Lino, você gera uma solução .NET organizada segundo as melhores práticas de arquitetura e modularização, com foco em performance, escalabilidade e facilidade de manutenção.

Criando um Novo Projeto

O comando lino project facilita a criação de novos projetos .NET de forma simples e eficiente. Com ele, você pode configurar a estrutura do seu projeto, selecionar as dependências necessárias e definir configurações de idiomas e infraestrutura.

Para criar um novo projeto, utilize o seguinte comando:

lino project new

Durante a execução, o CLI solicitará as seguintes informações:

  • Namespace do Projeto: Define o namespace principal da solução.
  • Nome de Exibição: Nome amigável exibido nas interfaces.
  • Linguagem de Programação: Atualmente, é suportado apenas C# (.NET).
  • Stack de Desenvolvimento: Atualmente, .NET 9 com Aspire.
  • Utilizar Analisadores de Código? Escolha entre Sim ou Não.
  • Utilizar Cache Distribuído? Escolha entre Sim ou Não.
  • Utilizar Comunicação Assíncrona? Escolha entre Sim ou Não.
  • Idioma dos Dados: Define o idioma utilizado para os nomes das entidades e outros dados informados no sistema.
  • Idiomas Suportados pela Aplicação: Permite adicionar suporte a até 10 idiomas para internacionalização (i18n).
  • Idioma Padrão: Define o idioma principal utilizado em APIs, mensagens de retorno, validações e na interface do usuário.

Após confirmar as informações, o Lino criará automaticamente a estrutura do projeto, conforme ilustrado abaixo:

MyApp/
├── MyApp.sln
├── src/
│   ├── Aspire/
│   │   ├── AppHost/
│   │   │   └── MyApp.AppHost.csproj
│   │   └── ServiceDefaults/
│   │       └── MyApp.ServiceDefaults.csproj
│   └── Services/
│       └── Shared/
│           ├── API/
│           │   └── MyApp.Shared.API.csproj
│           ├── Application/
│           │   └── MyApp.Shared.Application.csproj
│           ├── Domain/
│           │   └── MyApp.Shared.Domain.csproj
│           ├── Infrastructure/
│           │   └── MyApp.Shared.Infrastructure.csproj
│           └── Infrastructure.Persistence/
│               └── MyApp.Shared.Infrastructure.Persistence.csproj
└── tests/
    

Analisadores de Código

Os analisadores de código estático são ferramentas poderosas que ajudam a garantir a qualidade e a consistência do código durante o desenvolvimento. Eles fazem isso inspecionando o código-fonte sem a necessidade de execução, detectando erros, problemas de estilo e outras inconsistências.

Quando você escolhe habilitar os analisadores de código durante a criação do projeto, o CLI configurará automaticamente os seguintes pacotes para você:

  • StyleCop.Analyzers: Realiza verificações de estilo de código, como formatação de indentação, espaçamento e convenções de nomenclatura.
  • SonarAnalyzer.CSharp: Um conjunto de regras de qualidade de código e segurança, que ajuda a detectar falhas comuns e potenciais vulnerabilidades no código.
  • Roslynator.Analyzers: Oferece uma variedade de regras de qualidade e melhorias para o código C#, ajudando a identificar oportunidades de refatoração e otimização.

Vantagens dos Analisadores de Código:

  • Melhoria da Qualidade: Eles ajudam a manter o código limpo, legível e livre de problemas comuns.
  • Prevenção de Erros: Detectam erros antes de serem executados, permitindo que o desenvolvedor corrija problemas cedo no processo.
  • Padronização: Garantem que todos os desenvolvedores sigam as mesmas convenções e regras de estilo, melhorando a consistência do código.
  • Refatoração Assistida: Facilitam a refatoração do código, oferecendo sugestões para melhorias.

Ao ativar os analisadores de código, você tem uma forma proativa de melhorar a qualidade do seu código e reduzir o risco de falhas no ambiente de produção.

Cache Distribuído

O cache distribuído é uma técnica usada para melhorar a performance e escalabilidade de aplicações, armazenando dados frequentemente acessados em uma camada de cache externa ao banco de dados. Ele permite que as instâncias do aplicativo compartilhem dados em cache de forma eficiente, garantindo alta disponibilidade e redução do tempo de resposta.

Se você optar por habilitar o cache distribuído durante a criação do seu projeto, o Redis será integrado ao seu container Aspire, oferecendo um sistema de caching de alta disponibilidade.

Vantagens do Cache Distribuído:

  • Melhoria de Performance: Reduz o tempo de resposta das requisições, minimizando o acesso ao banco de dados.
  • Escalabilidade: Permite que a aplicação seja escalada horizontalmente, já que o cache pode ser acessado de diferentes instâncias de forma transparente.
  • Alta Disponibilidade: Com o Redis, o cache é mantido disponível mesmo em caso de falhas, oferecendo uma solução robusta para sistemas distribuídos.
  • Redução de Custo: Diminui a carga no banco de dados e no sistema, reduzindo a necessidade de processamento em requisições repetitivas.

Ao habilitar o cache distribuído, você estará melhorando significativamente a performance da sua aplicação, garantindo uma resposta mais rápida aos usuários e diminuindo a carga nos sistemas backend.

Comunicação Assíncrona

A comunicação assíncrona é uma abordagem que permite que sistemas e componentes se comuniquem de forma não bloqueante, ou seja, sem que o envio ou recebimento de dados interrompa o processamento de outras tarefas. Isso é especialmente útil em sistemas distribuídos e em situações de alta carga, onde a eficiência e a resiliência são cruciais.

Se você escolher habilitar a comunicação assíncrona, o RabbitMQ será integrado ao seu projeto, e o MassTransit será configurado para facilitar o uso dessa comunicação assíncrona em sua aplicação.

Vantagens da Comunicação Assíncrona:

  • Desempenho Aprimorado: Permite que as operações sejam realizadas em paralelo, sem bloquear o fluxo de execução do sistema.
  • Escalabilidade: Facilita a escalabilidade do sistema, permitindo que ele trate grandes volumes de dados e usuários simultâneos sem perder performance.
  • Resiliência: Em caso de falhas temporárias, a comunicação assíncrona permite que as mensagens sejam reprocessadas ou armazenadas para posterior processamento.
  • Desacoplamento: Os sistemas podem ser projetados para se comunicar sem depender diretamente de respostas imediatas, promovendo maior flexibilidade e organização.

A integração com o RabbitMQ e o uso do MassTransit tornam a comunicação entre os componentes mais eficiente e resiliente, ajudando a garantir a escalabilidade e a flexibilidade de sua aplicação.

Próximos Passos

Agora que você criou seu projeto .NET com o Lino, abra-o no seu editor de código favorito. Você pode usar o Visual Studio, Visual Studio Code ou qualquer outra IDE de sua preferência.

Com o projeto aberto, você pode começar a adicionar e configurar os serviços que compõem sua aplicação. Essa é a próxima etapa no fluxo de desenvolvimento.

Na próxima seção, vamos mostrar como criar e configurar esses serviços no seu novo projeto, preparando-o para crescer de forma organizada e escalável conforme as necessidades da sua aplicação.

Criar e gerenciar serviços

Após criar um projeto, o próximo passo é adicionar serviços. O Lino oferece uma maneira simples e intuitiva de criar serviços para sistemas monolíticos ou arquiteturas de microsserviços.

Para criar um novo serviço, use o seguinte comando:

lino service new

Durante o processo, o CLI solicitará as seguintes informações:

  • Namespace do Serviço: Define o nome e o namespace do serviço.
  • Nome de Exibição: Nome amigável que será exibido na interface.
  • Tipo de Serviço: Escolha entre simples ou modularizado.
  • Banco de Dados: Escolha entre PostgreSQL ou SQL Server.

Se o tipo escolhido for simples, também serão solicitadas as informações:

  • Estilo de Arquitetura: Atualmente apenas Clean Architecture é suportada.
  • Utilizar IDs fortemente tipados? Escolha sim ou não.

Tipos de Serviço

Serviço Simples: Estrutura mais enxuta, ideal para projetos monolíticos ou microsserviços com responsabilidades claras e isoladas.

Serviço Modularizado: Ideal para sistemas maiores que exigem maior organização e escalabilidade, permitindo dividir o serviço em módulos menores e focados, facilitando a manutenção e a evolução.

Independentemente do tipo, cada serviço terá seu próprio banco de dados. O suporte a IDs fortemente tipados é padrão para serviços simples; em serviços modularizados, essa decisão é feita por módulo.

A estrutura do Lino é flexível, permitindo a criação de serviços simples e modularizados dentro do mesmo projeto.

Estilo de Arquitetura

Todos os serviços no Lino utilizam a Clean Architecture, garantindo boas práticas de separação de responsabilidades, facilidade de manutenção e evolução do sistema.

Principais benefícios da Clean Architecture:

  • Desacoplamento: A lógica de negócios é isolada dos detalhes técnicos, aumentando a flexibilidade e a testabilidade.
  • Manutenibilidade: Separação clara entre camadas, facilitando mudanças sem impactar o sistema inteiro.
  • Testabilidade: A separação de responsabilidades facilita a criação de testes unitários e de integração.
  • Escalabilidade: Componentes podem ser modificados ou substituídos sem impactar a lógica de negócios.

Se optar por criar um serviço simples com Clean Architecture, a estrutura do projeto será semelhante a:

MyApp/
├── MyApp.sln
├── src/
│   ├── Aspire/
│   │   ├── AppHost/
│   │   │   └── MyApp.AppHost.csproj
│   │   └── ServiceDefaults/
│   │       └── MyApp.ServiceDefaults.csproj
│   ├── Integrations/
│   │   └── Internal/
│   │       └── MySimpleService/
│   │           └── Http/
│   │               ├── Clients/
│   │               │   └── MyApp.Integrations.MySimpleService.Http.Clients.csproj
│   │               └── Contracts/
│   │                   └── MyApp.Integrations.MySimpleService.Http.Contracts.csproj
│   └── Services/
│       ├── Shared/
│       │   ├── API/
│       │   │   └── MyApp.Shared.API.csproj
│       │   ├── Application/
│       │   │   └── MyApp.Shared.Application.csproj
│       │   ├── Domain/
│       │   │   └── MyApp.Shared.Domain.csproj
│       │   ├── Infrastructure/
│       │   │   └── MyApp.Shared.Infrastructure.csproj
│       │   └── Infrastructure.Persistence/
│       │       └── MyApp.Shared.Infrastructure.Persistence.csproj
│       └── MySimpleService/
│           ├── API/
│           │   └── MyApp.MySimpleService.API.csproj
│           ├── Application/
│           │   └── MyApp.MySimpleService.Application.csproj
│           ├── Domain/
│           │   └── MyApp.MySimpleService.Domain.csproj
│           ├── Infrastructure/
│           │   └── MyApp.MySimpleService.Infrastructure.csproj
│           ├── Infrastructure.Persistence/
│           │   └── MyApp.MySimpleService.Infrastructure.Persistence.csproj
│           └── IntegrationEvents/
│               └── MyApp.MySimpleService.IntegrationEvents.csproj
└── tests/
    └── Services/
        └── MySimpleService/
            ├── IntegrationTests/
            │   └── MyApp.MySimpleService.IntegrationTests.csproj
            └── UnitTests/
                └── MyApp.MySimpleService.UnitTests.csproj
    

Se optar por criar um serviço modularizado, o projeto será estruturado para permitir a adição de novos módulos de maneira organizada:

MyApp/
├── MyApp.sln
├── src/
│   ├── Aspire/
│   │   ├── AppHost/
│   │   │   └── MyApp.AppHost.csproj
│   │   └── ServiceDefaults/
│   │       └── MyApp.ServiceDefaults.csproj
│   └── Services/
│       ├── Shared/
│       │   ├── API/
│       │   │   └── MyApp.Shared.API.csproj
│       │   ├── Application/
│       │   │   └── MyApp.Shared.Application.csproj
│       │   ├── Domain/
│       │   │   └── MyApp.Shared.Domain.csproj
│       │   ├── Infrastructure/
│       │   │   └── MyApp.Shared.Infrastructure.csproj
│       │   └── Infrastructure.Persistence/
│       │       └── MyApp.Shared.Infrastructure.Persistence.csproj
│       └── MyModularService/
│           ├── Host/
│           │   └── MyApp.MyModularService.Host.csproj
│           ├── Infrastructure/
│           │   └── MyApp.MyModularService.Infrastructure.csproj
│           └── Modules/
└── tests/
    

IDs Fortemente Tipados

IDs fortemente tipados são uma prática para aumentar a segurança e a clareza do código, usando tipos específicos para identificadores (ID) em vez de tipos genéricos (como int ou guid).

Com IDs fortemente tipados, evita-se o uso incorreto de identificadores, reduzindo erros comuns. Por exemplo, um ID de usuário é representado por um tipo próprio em vez de um simples inteiro.

Vantagens dos IDs fortemente tipados:

  • Segurança de Tipo: Garante o uso correto dos IDs, impedindo misturas de tipos diferentes.
  • Clareza no Código: Cada tipo de ID é representado por uma classe específica, melhorando a legibilidade.
  • Facilidade de Refatoração: Mudanças no formato de um ID são aplicadas apenas no tipo correspondente, mantendo o restante seguro.
  • Redução de Erros: Evita a utilização de IDs em contextos incorretos.

Próximos passos para Serviços Modularizados

Após criar um serviço modularizado, o próximo passo é adicionar módulos. Módulos organizam a lógica de negócios e a infraestrutura de forma independente, tornando o sistema mais escalável e organizado.

Na próxima seção, aprenderemos como criar e gerenciar módulos dentro de serviços modularizados, aproveitando ao máximo a flexibilidade e escalabilidade dessa abordagem.

Criando e Gerenciando Módulos

Após criar um serviço modular, o próximo passo é adicionar módulos a ele. Módulos permitem organizar a lógica de negócios de forma independente, trazendo ainda mais escalabilidade e organização ao sistema.

Para criar um novo módulo, utilize o seguinte comando:

lino module new

Durante a execução, o CLI solicitará as seguintes informações:

  • Serviço: Define qual serviço o novo módulo será criado.
  • Namespace do Módulo: Define o nome e o namespace do módulo.
  • Nome de Exibição: Nome amigável exibido nas interfaces.
  • Estilo Arquitetural: Atualmente, apenas Clean Architecture.
  • Utilizar Strongly Typed ID? Escolha entre Sim ou Não.

Ao final, o Lino gerará o novo módulo mantendo a estrutura do seu serviço modular:

MyApp/
├── MyApp.sln
├── src/
│   ├── Aspire/
│   │   ├── AppHost/
│   │   │   └── MyApp.AppHost.csproj
│   │   └── ServiceDefaults/
│   │       └── MyApp.ServiceDefaults.csproj
│   ├── Integrations/
│   │   └── Internal/
│   │       └── MyModularService/
│   │           └── MyModule/
│   │               └── Http/
│   │                   ├── Clients/
│   │                   │   └── MyApp.Integrations.MyModularService.MyModule.Http.Clients.csproj
│   │                   └── Contracts/
│   │                       └── MyApp.Integrations.MyModularService.MyModule.Http.Contracts.csproj
│   └── Services/
│       ├── Shared/
│       │   ├── API/
│       │   │   └── MyApp.Shared.API.csproj
│       │   ├── Application/
│       │   │   └── MyApp.Shared.Application.csproj
│       │   ├── Domain/
│       │   │   └── MyApp.Shared.Domain.csproj
│       │   ├── Infrastructure/
│       │   │   └── MyApp.Shared.Infrastructure.csproj
│       │   └── Infrastructure.Persistence/
│       │       └── MyApp.Shared.Infrastructure.Persistence.csproj
│       └── MyModularService/
│           ├── Host/
│           │   └── MyApp.MyModularService.Host.csproj
│           ├── Infrastructure/
│           │   └── MyApp.MyModularService.Infrastructure.csproj
│           └── Modules/
│               └── MyModule/
│                   ├── API/
│                   │   └── MyApp.MyModularService.MyModule.API.csproj
│                   ├── Application/
│                   │   └── MyApp.MyModularService.MyModule.Application.csproj
│                   ├── Domain/
│                   │   └── MyApp.MyModularService.MyModule.Domain.csproj
│                   ├── Infrastructure/
│                   │   └── MyApp.MyModularService.MyModule.Infrastructure.csproj
│                   ├── Infrastructure.Persistence/
│                   │   └── MyApp.MyModularService.MyModule.Infrastructure.Persistence.csproj
│                   └── IntegrationEvents/
│                       └── MyApp.MyModularService.MyModule.IntegrationEvents.csproj
└── tests/
    └── Services/
        └── MyModularService/
            └── Modules/
                └── MyModule/
                    ├── IntegrationTests/
                    │   └── MyApp.MyModularService.MyModule.IntegrationTests.csproj
                    └── UnitTests/
                        └── MyApp.MyModularService.MyModule.UnitTests.csproj

Estrutura de Banco de Dados

É importante destacar que o banco de dados está vinculado ao serviço. Dentro de um serviço modular, cada módulo é representado por seu próprio schema no banco de dados associado. Essa abordagem proporciona isolamento e organização, sem a necessidade de criar múltiplos bancos de dados distintos.

Sobre a Independência entre Módulos

Assim como os serviços não possuem dependências diretas entre si, os módulos também são criados como projetos independentes dentro do serviço.

Vantagens desse desacoplamento:

  • Isolamento: Cada módulo pode evoluir de forma independente, facilitando a manutenção e a evolução contínua.
  • Organização: A aplicação torna-se verdadeiramente modular, respeitando os limites de contexto (Bounded Contexts) e promovendo boas práticas de arquitetura de software.
  • Flexibilidade: Permite adicionar, remover ou refatorar módulos sem impactar diretamente outros módulos do serviço.
  • Facilidade de testes: Cada módulo pode ser testado de forma isolada, aumentando a confiabilidade e a qualidade do sistema.

Com isso, concluímos o processo de criação de módulos. Nos próximos tópicos, veremos como estruturar os elementos internos de um módulo, como entidades, objetos de valor, enumerações, comandos, consultas, APIs, integrações e muito mais.

Ocorreu um erro não tratado. Recarregar 🗙