Strutturazione del progetto

Lino è stato sviluppato per semplificare la creazione di progetti scalabili e modulari in modo efficiente. Offre una soluzione ben strutturata, con una chiara separazione delle responsabilità tra i livelli, ed è pronto a crescere con l'evolversi delle esigenze del tuo progetto.


Creando un progetto con Lino, generi una soluzione .NET organizzata secondo le migliori pratiche di architettura e modularizzazione, con particolare attenzione a prestazioni, scalabilità e facilità di manutenzione.

Creazione di un Nuovo Progetto

Il comando lino project semplifica la creazione di nuovi progetti .NET in modo semplice ed efficiente. Con esso, puoi configurare la struttura del tuo progetto, selezionare le dipendenze necessarie e definire le configurazioni di lingua e infrastruttura.

Per creare un nuovo progetto, utilizza il seguente comando:

lino project new

Durante l'esecuzione, l'interfaccia a linea di comando ti chiederà le seguenti informazioni:

  • Namespace del Progetto: Definisce lo spazio dei nomi principale della soluzione.
  • Nome di Visualizzazione: Nome amichevole visualizzato nelle interfacce.
  • Lingua di Programmazione: Attualmente è supportato solo C# (.NET).
  • Stack di Sviluppo: Attualmente, .NET 10 con Aspire.
  • Utilizzare Analizzatori di Codice? Scegli tra Sì o No.
  • Utilizzare Cache Distribuita? Scegli tra Sì o No.
  • Utilizzare Comunicazione Asincrona? Scegli tra Sì o No.
  • Lingua dei Dati: Definisce la lingua utilizzata per i nomi delle entità e altri dati nel sistema.
  • Lingue Supportate dall'Applicazione: Permette di aggiungere il supporto fino a 10 lingue per l'internazionalizzazione (i18n).
  • Lingua Predefinita: Definisce la lingua principale utilizzata nelle API, nei messaggi di ritorno, nelle convalide e nell'interfaccia utente.

Dopo aver confermato le informazioni, Lino creerà automaticamente la struttura del progetto, come mostrato di seguito:

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/
    

Analizzatori di Codice

Gli analizzatori di codice statico sono strumenti potenti che aiutano a garantire la qualità e la coerenza del codice durante lo sviluppo. Lo fanno ispezionando il codice sorgente senza la necessità di eseguire il programma, rilevando errori, problemi di stile e altre incoerenze.

Quando scegli di abilitare gli analizzatori di codice durante la creazione del progetto, l'interfaccia a linea di comando configurerà automaticamente i seguenti pacchetti per te:

  • StyleCop.Analyzers: Esegue verifiche sullo stile del codice, come la formattazione dell'indentazione, degli spazi e delle convenzioni di denominazione.
  • SonarAnalyzer.CSharp: Un set di regole per la qualità del codice e la sicurezza, che aiuta a rilevare errori comuni e vulnerabilità potenziali nel codice.
  • Roslynator.Analyzers: Offre una varietà di regole per migliorare la qualità del codice C#, aiutando a identificare opportunità di refactoring e ottimizzazione.

Vantaggi degli Analizzatori di Codice:

  • Miglioramento della Qualità: Aiutano a mantenere il codice pulito, leggibile e privo di errori comuni.
  • Prevenzione degli Errori: Rilevano gli errori prima che vengano eseguiti, permettendo agli sviluppatori di correggere i problemi in anticipo.
  • Standardizzazione: Garantisce che tutti gli sviluppatori seguano le stesse convenzioni e regole di stile, migliorando la coerenza del codice.
  • Refactoring Assistito: Facilita il refactoring del codice offrendo suggerimenti per miglioramenti.

Abilitando gli analizzatori di codice, hai un modo proattivo per migliorare la qualità del tuo codice e ridurre il rischio di errori in produzione.

Cache Distribuita

La cache distribuita è una tecnica utilizzata per migliorare le prestazioni e la scalabilità delle applicazioni, memorizzando i dati frequentemente accessibili in una cache esterna al database. Consente alle istanze dell'applicazione di condividere i dati in cache in modo efficiente, garantendo alta disponibilità e riducendo i tempi di risposta.

Se scegli di abilitare la cache distribuita durante la creazione del tuo progetto, Redis sarà integrato nel tuo container Aspire, offrendo un sistema di caching ad alta disponibilità.

Vantaggi della Cache Distribuita:

  • Miglioramento delle Prestazioni: Riduce i tempi di risposta delle richieste, minimizzando l'accesso al database.
  • Scalabilità: Permette di scalare l'applicazione orizzontalmente, poiché la cache può essere acceduta da diverse istanze in modo trasparente.
  • Alta Disponibilità: Con Redis, la cache rimane disponibile anche in caso di guasti, offrendo una soluzione robusta per sistemi distribuiti.
  • Riduzione dei Costi: Diminuisce il carico sul database e sul sistema, riducendo la necessità di elaborazione per richieste ripetitive.

Abilitando la cache distribuita, migliorerai significativamente le prestazioni della tua applicazione, garantendo una risposta più rapida per gli utenti e riducendo il carico sui sistemi backend.

Comunicazione Asincrona

La comunicazione asincrona è un approccio che consente ai sistemi e ai componenti di comunicare in modo non bloccante, ovvero senza che l'invio o la ricezione dei dati interrompano l'esecuzione di altre attività. Questo è particolarmente utile nei sistemi distribuiti e in situazioni di carico elevato, dove l'efficienza e la resilienza sono fondamentali.

Se scegli di abilitare la comunicazione asincrona, RabbitMQ sarà integrato nel tuo progetto e MassTransit sarà configurato per facilitare l'uso di questa comunicazione asincrona nella tua applicazione.

Vantaggi della Comunicazione Asincrona:

  • Prestazioni Migliorate: Permette di eseguire operazioni in parallelo senza bloccare il flusso di esecuzione del sistema.
  • Scalabilità: Facilita la scalabilità del sistema, permettendo di gestire grandi volumi di dati e utenti simultanei senza compromettere le prestazioni.
  • Resilienza: In caso di guasti temporanei, la comunicazione asincrona consente di riprocessare o archiviare i messaggi per un'elaborazione successiva.
  • Decoupling: I sistemi possono essere progettati per comunicare senza dipendere direttamente da risposte immediate, consentendo maggiore flessibilità e organizzazione.

L'integrazione con RabbitMQ e l'uso di MassTransit rendono la comunicazione tra i componenti più efficiente e resiliente, contribuendo a garantire la scalabilità e la flessibilità della tua applicazione.

Prossimi Passi

Ora che hai creato il tuo progetto .NET con Lino, aprilo nel tuo editor di codice preferito. Puoi utilizzare Visual Studio, Visual Studio Code o qualsiasi altro IDE di tua scelta.

Una volta aperto il progetto, puoi iniziare ad aggiungere e configurare i servizi che compongono la tua applicazione. Questa è la prossima fase nel flusso di sviluppo.

Nella prossima sezione, ti mostreremo come creare e configurare questi servizi nel tuo nuovo progetto, preparandolo a crescere in modo organizzato e scalabile in base alle esigenze della tua applicazione.

Creazione e gestione dei servizi

Una volta creato il progetto, il passo successivo è aggiungere i servizi. Lino offre un modo semplice e intuitivo per creare servizi, che possono essere utilizzati in sistemi monolitici o architetture a microservizi.

Per creare un nuovo servizio, utilizza il seguente comando:

lino service new

Durante l'esecuzione, il CLI richiederà le seguenti informazioni:

  • Namespace del servizio: Definisce il nome e il namespace del servizio.
  • Nome visualizzato: Nome amichevole visualizzato nelle interfacce.
  • Tipo di servizio: Scegli tra Semplice o Modulare.
  • Database: Scegli tra PostgreSQL o SQL Server.

Se il tipo di servizio scelto è Semplice, verranno richieste anche le seguenti informazioni:

  • Stile architetturale: Attualmente solo Clean Architecture.
  • Utilizzare Strongly Typed ID? Scegli tra Sì o No.

Tipi di servizio

Servizio semplice: Un servizio semplice ha una struttura più snella, adatta per sistemi monolitici o progetti di microservizi in cui ogni servizio ha una responsabilità indipendente.

Servizio modulare: Per sistemi più grandi che richiedono una maggiore organizzazione e scalabilità, è possibile optare per un servizio modulare. Questo tipo consente di suddividere il servizio in moduli più piccoli e specifici, facilitando la manutenzione e la crescita del sistema.

Che tu scelga un servizio semplice o modulare, il database sarà unico per ogni servizio. L'architettura e l'uso di Strongly Typed IDs si applicano ai servizi semplici. Per i servizi modulari, la decisione sarà presa a livello di ogni modulo creato all'interno del servizio.

La struttura di Lino è flessibile e consente la creazione di servizi semplici e modulari all'interno dello stesso progetto.

Stile architetturale

Lino applica già Clean Architecture a tutti i servizi. Questo garantisce che l'applicazione segua un'architettura ben strutturata, promuovendo la separazione delle responsabilità e facilitando la manutenzione e la scalabilità.

Vantaggi di Clean Architecture:

  • Disaccoppiamento: La logica di business è indipendente dai dettagli tecnici, offrendo maggiore flessibilità e testabilità.
  • Manutenibilità: Poiché i layer sono ben separati, è più facile apportare modifiche senza influire su altre parti del sistema.
  • Testabilità: La separazione delle preoccupazioni facilita la creazione di test unitari e di integrazione per ogni layer in modo indipendente.
  • Scalabilità: Il progetto è più facile da scalare poiché i componenti possono essere modificati o sostituiti senza influire sulla logica di business.

Se scegli di creare un servizio semplice, utilizzando l'implementazione di Clean Architecture, il progetto sarà generato con la seguente struttura:

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
│       └── 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
│           └── Integration.Events/
│               └── MyApp.MySimpleService.Integration.Events.csproj
└── tests/
    

Se scegli un servizio modulare, il progetto adotterà la seguente struttura, consentendo di aggiungere nuovi moduli in modo flessibile e organizzato durante lo sviluppo del servizio:

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/
    

Strongly Typed ID

Strongly Typed ID è un approccio che mira a migliorare la sicurezza e la chiarezza del codice assicurandosi che i tipi di identificatori (ID) siano più specifici e fortemente tipizzati, evitando l'uso di tipi generici come int o guid per rappresentare entità uniche.

Con Strongly Typed ID, invece di usare tipi generici come un numero intero per rappresentare un ID utente, creeresti un tipo specifico per l'ID utente. Questo aiuta a evitare errori comuni, come l'uso improprio di ID di tipi diversi in contesti sbagliati.

Vantaggi dell'uso di Strongly Typed IDs:

  • Sicurezza del tipo: Garantisce che gli ID vengano utilizzati correttamente, evitando la mescolanza di ID di tipi diversi, come ID utente con ID prodotto.
  • Chiarezza: Il codice diventa più chiaro poiché ogni tipo di ID è esplicitamente rappresentato da una classe specifica.
  • Facilità di refactoring: Se il tipo di identificatore deve cambiare, basta modificare solo il tipo specifico di ID e il resto del codice rimarrà sicuro.
  • Evita errori: Riduce la possibilità di bug legati all'uso scorretto di identificatori generici in contesti sbagliati.

Creazione e gestione dei moduli

Una volta creato un servizio modulare, il passo successivo è aggiungere i moduli. I moduli consentono di organizzare la logica aziendale in modo indipendente, portando così maggiore scalabilità e organizzazione al sistema.

Per creare un nuovo modulo, utilizza il seguente comando:

lino module new

Durante l'esecuzione, la CLI chiederà le seguenti informazioni:

  • Servizio: Definisce a quale servizio sarà aggiunto il nuovo modulo.
  • Namespace del modulo: Definisce il nome e il namespace del modulo.
  • Nome di visualizzazione: Nome amichevole visualizzato nelle interfacce.
  • Stile architetturale: Attualmente solo Clean Architecture.
  • Utilizzare ID fortemente tipizzati? Scegli tra Sì o No.

Alla fine, Lino genererà il nuovo modulo mantenendo la struttura del tuo servizio modulare:

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/
│               └── 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
│                   └── Integration.Events/
│                       └── MyApp.MyModularService.MyModule.Integration.Events.csproj
└── tests/

Struttura del database

È importante sottolineare che il database è legato al servizio. All'interno di un servizio modulare, ogni modulo è rappresentato dal proprio schema nel database associato. Questo approccio fornisce isolamento e organizzazione, senza la necessità di creare più database distinti.

Sull'indipendenza tra i moduli

Così come i servizi non hanno dipendenze dirette tra loro, anche i moduli vengono creati come progetti indipendenti all'interno del servizio.

Vantaggi di questo disaccoppiamento:

  • Isolamento: Ogni modulo può evolversi in modo indipendente, facilitando la manutenzione e l'evoluzione continua.
  • Organizzazione: L'applicazione diventa veramente modulare, rispettando i confini del contesto (Bounded Contexts) e promuovendo buone pratiche di architettura software.
  • Flessibilità: Permette di aggiungere, rimuovere o rifattorizzare i moduli senza influire direttamente sugli altri moduli del servizio.
  • Facilità nei test: Ogni modulo può essere testato in modo isolato, aumentando l'affidabilità e la qualità del sistema.

Con questo, concludiamo il processo di creazione dei moduli. Nei prossimi argomenti, vedremo come strutturare gli elementi interni di un modulo, come entità, oggetti di valore, enumerazioni, comandi, query, API, integrazioni e molto altro.

Si è verificato un errore non gestito. Ricarica 🗙