2010-04-03 27 views
10

appena creato un secondo su SO a chiedere questo :)In un approccio DDD, questo esempio è modellato correttamente?

Assumendo questo esempio semplificato: la costruzione di un'applicazione web per gestire i progetti ...
L'applicazione ha i seguenti requisiti/regole.

1) Gli utenti devono essere in grado di creare progetti inserendo il nome del progetto.
2) I nomi dei progetti non possono essere vuoti.
3) Due progetti non possono avere lo stesso nome.

Utilizzo un'architettura a 4 livelli (Interfaccia utente, Applicazione, Dominio, Infrastruttura).
Sul mio Application Layer ho la seguente classe ProjectService.cs:

public class ProjectService 
{ 
    private IProjectRepository ProjectRepo { get; set; } 

    public ProjectService(IProjectRepository projectRepo) 
    { 
     ProjectRepo = projectRepo; 
    } 

    public void CreateNewProject(string name) 
    { 
     IList<Project> projects = ProjectRepo.GetProjectsByName(name); 
     if (projects.Count > 0) throw new Exception("Project name already exists."); 

     Project project = new Project(name); 
     ProjectRepo.InsertProject(project); 
    } 
} 

Sul mio strato di dominio, ho la classe Project.cs e l'interfaccia IProjectRepository.cs:

public class Project 
{ 
    public int ProjectID { get; private set; } 
    public string Name { get; private set; } 

    public Project(string name) 
    { 
     ValidateName(name); 
     Name = name; 
    } 

    private void ValidateName(string name) 
    { 
     if (name == null || name.Equals(string.Empty)) 
     { 
      throw new Exception("Project name cannot be empty or null."); 
     } 
    } 
} 




public interface IProjectRepository 
{ 
    void InsertProject(Project project); 
    IList<Project> GetProjectsByName(string projectName); 
} 

Sul mio Livello infrastruttura, ho l'implementazione di IProjectRepository che esegue l'interrogazione effettiva (il codice è irrilevante).


non mi piace due cose su questo progetto:

1) Ho letto che le interfacce repository dovrebbe essere una parte del dominio, ma le implementazioni non dovrebbe. Questo non ha senso per me dal momento che penso che il dominio non dovrebbe chiamare i metodi di repository (ignoranza di persistenza), che dovrebbe essere una responsabilità dei servizi nel livello dell'applicazione. (Qualcosa mi dice che sono terribilmente storto.)

2) Il processo di creazione di un nuovo progetto prevede due convalide (non nulle e non duplicate). Nel mio progetto sopra, quelle due convalide sono sparse in due luoghi diversi, rendendo più difficile (imho) vedere cosa sta succedendo.

Quindi, la mia domanda è, dal punto di vista del DDD, è modellato correttamente o lo si farà in un modo diverso?

risposta

1

Penso che parte della confusione con (1) è che ti manca un livello - inserisci un livello di servizio nella tua architettura e il tuo problema scompare come per magia. È possibile inserire il servizio e l'implementazione del repository nel livello di servizio, ad esempio, si dispone di un servizio che utilizza un'implementazione concreta del repository. Altri servizi sono liberi di scegliere un'implementazione alternativa del repository, se lo desiderano. La tua applicazione è libera di scegliere qualsiasi interfaccia di servizio che gli piace. Detto questo, non sono sicuro che sia davvero importante nella maggior parte dei casi. In quasi tutte le mie applicazioni ho un "dominio/datalayer" fondamentalmente fisso. Potrei suddividere un repository su di esso o meno a seconda di quanto sia complicata la logica di business. Lo stesso vale per il servizio - potrebbe semplicemente non essere necessario se il progetto non è molto complicato. Se diventa così tardi, posso sempre refactoring. In genere avrei messo il mio repository nello stesso progetto del mio contesto dati (usando LINQ) e, se ci fosse un servizio, sarebbe in un progetto separato (perché tipicamente sarebbe esposto anche come servizio web).

Riguardo a (2) è necessario pensare al problema da una prospettiva di concorrenza. Il controllo di un nome duplicato è meglio gestito da un vincolo del database, se possibile. Penso che questo sia il modo più semplice per far rispettare questa logica. Puoi certamente verificare se c'è un duplicato prima di tentare un inserto, ma a meno che tu non lo faccia all'interno di una transazione non puoi garantire che un altro processo non arrivi e inserirne uno tra il tuo assegno e il tuo inserto.Il vincolo del database risolve questo problema. Lo spostamento del controllo nella logica di inserimento (stessa transazione) risolve anche il problema, ma a prescindere penso che sia necessario essere pronti a gestirlo come un errore di inserimento e (o invece di) un errore di convalida.

+0

Per quanto riguarda (1), penso che il mio livello di applicazione potrebbe servire allo scopo di un livello di servizio, se avessi un altro strato penso che potrei finire con livelli senza significato o responsabilità condivisa tra i livelli. Quando parli della complessità del design, sono completamente d'accordo con te. Ho usato un approccio 'Active Records Pattern' per la maggior parte delle mie applicazioni, e quel pattern potrebbe sembrare più adatto a risolvere questo esempio. Ho intenzionalmente lasciato questo esempio semplicistico, ma sto cercando di imparare come modellare correttamente usando un modello di deposito, ecco perché mi sto allontanando dal pattern AR. – Tag

+0

Per quanto riguarda (2), il tuo suggerimento ha perfettamente senso per me e penso che sia davvero l'opzione migliore in questo caso. – Tag

2

Il processo di creazione di un nuovo progetto prevede due convalide (non nulle e non duplicate). Nel mio progetto sopra, quelle due convalide sono sparse in due luoghi diversi, rendendo più difficile (imho) vedere cosa sta succedendo.

progetto non può e non deve essere a conoscenza di tutti i progetti in applicazioni (voce di per sé non dovrebbe essere a conoscenza di tutti gli altri elementi in lista), quindi -. È la responsabilità del servizio di dominio (instead of application service controllare Evans prenota per capire la differenza esatta).

Esistono molti tipi di convalida. E there can't be universal validation mechanism. DDD dice solo che devi mettere la convalida del dominio nel modello di dominio.

Problemi correlati