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 9 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 β βββ 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 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 β βββ 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
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.