Come organizzare il codice in base alla funzionalità

1

Uso le classi di servizio MVC + nel mio progetto. La struttura dei miei progetti è la seguente:

-MySolution.Web
-MySolution.Models
-MySolution.Services
-MySolution.Common

MySolution.Web è un progetto di applicazione web asp.net. MySolution.Models memorizza le classi del modello che si associano direttamente al database utilizzando Entity Framework. MySolution.Services è dove mantengo tutte le regole aziendali e recupero i dati dal database.

MySolution.Web utilizza MySolution.Services per ottenere dati mappati dal database e visualizzarli, ad es. nel mio controller chiamo _customerService.GetActiveCustomers() .

Funziona bene per il recupero di entità correlate al database, ma ho un dilemma in cui inserire classi che non hanno nulla a che fare con il database e fare altre cose. Ecco un esempio:

Devo ottenere un paio di articoli da un sito Web e visualizzare informazioni. Potrei avere classi come ArticlesRepository , Article , ArticleParagraph , ecc. Ora, potrei inserirle in MySolution.Services e MySolution.Models , ma questo molto rapidamente ingombrerà questi progetti.

Stavo pensando di creare un nuovo progetto per questo chiamato MySolution.Articles a cui fare riferimento con MySolution.Web . Ora ci sono solo 3 classi e non so se realizzare un intero progetto per questo sia una buona idea.

    
posta FCin 12.07.2018 - 11:15
fonte

4 risposte

1

Per Enterprise Architecture, puoi seguire le convenzioni ampiamente adottate dagli sviluppatori di tutto il mondo. La proposta consiste nell'usare l'architettura N-Layered separata dalle preoccupazioni, il livello principale è il modello di dominio, seguito da Data Access Layer (DAL), Business Logic Layer (BLL) e Presentation o GUI, in cui si inserisce l'utente interfacce.

Il problema che hai menzionato, potrebbe facilmente essere risolto aggiungendo un layer esclusivo per preoccuparti del Database (il livello di accesso ai dati), il tuo attuale livello Modelli, dovrebbe avere solo le entità, i valori oggetto, le relazioni e le regole aziendali .

Il Business Layer (lo hai chiamato MySolution.Services, ed è un buon nome), è responsabile per collegare i Dati con i Modelli e consegnarli al livello di presentazione, che tu l'hai chiamato MySolution.Web.

Se lo desideri, puoi leggere ulteriori informazioni su Enterprise Architecture e ti consiglio di leggere Domain-Driven Design di Eric Evans e Enterprise Architecture di Martin Fowler.

Ricorda, non esiste un modello per l'architettura, le tue decisioni dovrebbero essere guidate dal dominio del problema che stai cercando di risolvere.

Spero sia stato utile per te, pensaci e buon codice!

    
risposta data 18.07.2018 - 20:22
fonte
0

Mentre la creazione di un progetto MySolution.Articles è un approccio perfetto, non è l'unico modo.

Ecco un altro approccio. Non sto dicendo che è perfetto per la tua situazione, ma potrebbe valere la pena di prendere in considerazione:

Non ci sono problemi con l'inclusione di articoli nel progetto MySolution.Models con tutti gli altri modelli.

Il fatto che gli articoli non siano mantenuti nello stesso database, o in un database, dovrebbe essere irrilevante. Le tue classi MySolution.Services devono recuperare i tuoi Clienti da un repository clienti e gli articoli da un repository di articoli senza dover sapere o preoccuparsi di quale sia il meccanismo di persistenza sottostante. Potrebbe essere un database, ma potrebbe anche essere un servizio Web, un file di testo, una pagina Web o qualsiasi altra cosa. Al di fuori dei repository, non importa.

In tal caso, i tuoi articoli saranno trattati come i tuoi clienti e ogni altro modello nella tua soluzione. Non sono sicuro di cosa intendi per "ingombrerà molto rapidamente questi progetti" in riferimento a Servizi e Modelli. Un articolo è uno dei tuoi modelli e deve essere manipolato con un servizio, proprio come il resto della tua app. Appartengono a questi progetti proprio come fanno i clienti.

Questo mantiene la coerenza della tua architettura e riduce il carico cognitivo del lavoro con i tuoi Modelli. Non devi ricordare che queste classi sono recuperate da quel database , quindi il loro codice è qui , mentre questi classi che ottengo da un servizio web, quindi il loro codice è qui , e queste classi provengono da un file di testo, quindi < em> loro sono laggiù e così via.

    
risposta data 12.07.2018 - 17:18
fonte
0

Vorrei condividere la mia esperienza personale nell'esplorazione di questo esatto problema nella migrazione di un'applicazione WinForms in un'applicazione web ASP.NET Core. Vorrei notare che questa soluzione organizzava principalmente servizi di backend che fornivano servizi di integrazione / orchestrazione a un front-end.

Come accennato in Ant P, esiste una scelta tra il raggruppamento del codice in unità "verticale" (funzionale) e "orizzontale" (livello / classe). La mia preferenza personale è quella di organizzare sempre codice e spazi dei nomi in unità schierabili tramite l'approccio "verticale" anziché raggruppare tutte le "entità" in un ampio spazio di nomi Models trasversale e tutto " dati che ottengono / elaborano le classi "in uno spazio dei nomi Services separato secondo l'approccio" orizzontale ".

Dalla tua domanda e dai tuoi commenti, presumo che alla fine desideri esporre API per servire più siti web, probabilmente da uno spazio dei nomi MySolution.Web.Controllers . Attualmente, tutto il mio codice è in un progetto a causa di una decisione precedente dello sviluppatore, ma organizzo tutti gli altri moduli in modo che possano essere facilmente estrapolati in un altro progetto quando necessario .

Per ottenere un approccio "verticale", ho uno spazio dei nomi Domains che contiene agnostico dell'applicazione riguarda separato da specifiche dell'applicazione come il tuo fratello Controllers o ViewModels spazi dei nomi. Non so quanto sia flessibile la tua attuale struttura della soluzione , ma nel mio spazio dei nomi Domains ci sono categorie funzionali come OrderManagement e ShippingServices . Ogni "categoria funzionale" può annidare ulteriori spazi dei nomi che si specializzano infine in classi di "implementatori" o fonti di terze parti. Per esempio. Domains.OrderManagement.SomeSalesChannel conterrà tutto il codice per interagire con quel canale di vendita nel contesto della gestione degli ordini. Nel tuo caso, avresti uno spazio dei nomi Domains.ArticleObtainment o il tuo nome migliore per questo problema.

Una volta che ognuno di questi "nodi foglia" di funzionalità viene stabilito all'interno dello spazio dei nomi Domains , quindi in ogni foglia è possibile avere qualsiasi combinazione dei seguenti spazi dei nomi:

  • Entities : tutti i tipi di dominio con identità persistente indipendente dal backing store (come rilevato da Eric King). Vedi Domain Driven Design . Questo potrebbe avere il tuo Article e probabilmente ArticleParagraph a condizione che abbiano un'identità persistente.
  • ValueObjects : tipi non persistenti, enumerazioni, 'enumeri / involucri sicuri per tipo'
  • Utilities : problemi di carattere funzionale che eseguono solo elaborazione e calcoli senza "presentare" alcuni backing store o dati di terze parti. Questo potrebbe avere il tuo IRentCalculator ecc.
  • (Data)Services : repository, "client" / endpoint e interfacce a qualche componente consumabile di un implementazione DbContext che serve a fonte tutti gli elementi nel suo fratello Entities namespace e nessun altro . Questo potrebbe avere il tuo RentService o ArticleRepository .

Fondamentalmente, ogni "nodo foglia" di funzionalità dovrebbe contenere tutto il necessario per servire quella categoria di funzionalità ed essere estratto in un progetto separato o "suite funzionale" per il riutilizzo attraverso i progetti quando necessario. Ora, se usi Visual Studio, come menziona Flater, dovrebbe assegnare automaticamente spazi dei nomi alle tue classi che corrispondono alla struttura della cartella della soluzione; è da queste cartelle di indipendenza funzionale che puoi estrarle in progetti separati a tuo piacimento.

Se desideri riutilizzare il codice o creare un'astrazione DI / IoC per più moduli da sfruttare, puoi aggiungere uno spazio dei nomi Base all'interno di una categoria funzionale contenente interfacce o classi astratte per ognuna delle categorie di spazio dei nomi finali sopra menzionate e hanno solo fratelli e sorelle in tale spazio di nomi Base che li utilizzano o li implementano. All'interno di questo sistema, puoi definire le tue regole implicite sul fatto che uno spazio dei nomi dovrebbe poter dipendere da un altro.

In una nota finale, per "specifiche dell'applicazione" separate dallo spazio dei nomi Domains , ho uno spazio dei nomi DataLinks per incapsulare le trasformazioni tra i tipi negli spazi dei nomi Domains o ViewModels . Quindi ho uno spazio dei nomi DataFlows separato che può dipendere da DataLinks per aggregare, instradare o orchestrare le transazioni tra quegli elementi nello spazio dei nomi Domains . Infine, ho i miei controller solo in base a questi DataFlows o DataServices come necessario.

    
risposta data 16.07.2018 - 05:41
fonte
0

Più progetti è sempre una buona cosa.

  • Applica la separazione delle tue classi
  • Arresta le modifiche in un progetto interrompendo la compilazione di un'altra. Il secondo progetto deve cambiare il suo binario di riferimento prima che la compilazione abbia esito negativo.
  • Puoi pubblicare la dll compilata come pacchetto nuget da usare altrove
  • Espone riferimenti circolari
  • Espone una cattiva separazione delle preoccupazioni, come puoi vedere quando hai molti altri progetti che fanno riferimento a progetti non correlati

La cosa più importante è limitare l'ambito di un bit di codice compilato, ti permette di finire i bit di codice e non cambiarli mai più.

Per decidere cosa va inserito in un nuovo progetto e cosa viene messo in evidenza, la mia semplice regola è: "Un set di modelli per database".

In teoria tutto in un singolo database è strongmente accoppiato o potenzialmente strongmente accoppiato e quindi non dovrebbe essere diviso.

Se necessario, è possibile dividere ulteriormente la logica aziendale nei propri servizi. ciascuno dei quali utilizza un modello e un repository con scope DB

* Regola avanzata: per schema del database

    
risposta data 12.07.2018 - 12:45
fonte

Leggi altre domande sui tag