Background
I'm trying to create a simple application to really understand the whole stack of DDD+TDD+etc. My goal is to dynamically inject the DAL repository classes at runtime. This keeps my Domain and Application Services layers testable. I plan on using "poor man's DI" to accomplish this for now ... so I would do this in a simple Console application near startup:
// Poor man's DI, injecting DAL repository classes at runtime var productRepository = new SimpleOrder.Repository.ProductRespository(); var customerRepository = new SimpleOrder.Repository.CustomerRepository(); var orderRepository = new SimpleOrder.Repository.OrderRepository(); // Constructor injection into this class in the Application Services layer, // SimpleOrder.ApplicationFacade OrderEntry oe = new OrderEntry(customerRepository, orderRepository, productRepository);
To accomplish this dependency injection, I've created three repository interfaces:
-- ICustomerRepository -- IOrderRepository -- IProductRespository
A typical implementation:
namespace SimpleOrder.Domain.Interfaces { public interface ICustomerRepository { Customer GetCustomerById(int customerId); void SaveCustomer(Customer customer); } }
** Notice that SaveCustomer references the Customer model class defined in the domain layer. This is typical of the other repositories.
HOWEVER I'm not sure which project / layer they should be implemented in. I have 5 projects in a solution:
SimpleOrder.ConsoleClient (presentation) -- I want to inject the specific implementation of the domain from here as the application
SimpleOrder.ApplicationFacade (application services) -- chunky higher-level, coarser-grained methods orchestrating lower-level methods in the domain
SimpleOrder.Contracts -- DTO classes used for communication between presentation and application services
SimpleOrder.Domain (domain / bll) -- domain model classes Customer, Order, OrderItem, Product
SimpleOrder.Repository (dal) -- implements the repository interfaces
Here are my options as I see it:
Option 1: Define the repository interfaces in SimpleOrder.Contracts ...
PRO: this is where I think they should belong because I created this to share contracts between various concerns / layers. ex., DTOs are defined here.
CON: however the method signatures in of each interface references Domain model classes.
This means that I would have to add a reference to the SimpleOrder.Domain, but when the
SimpleOrder.Contracts is referenced in another project, it will have to carry
SimpleOrder.Domain along for the ride. This doesn't feel right.
Option 2: Same scenario as above, but I ALSO define interfaces for each Domain model class in the SimpleOrder.Contracts so I can break the coupling of the repository interfaces to the actual model classes.
Example:
namespace SimpleOrder.Domain.Interfaces { public interface ICustomerRepository { ICustomer** GetCustomerById(int customerId); void SaveCustomer(ICustomer customer); } public interface ICustomer { int CustomerId { get; set; } string Name { get; set; } System.Collections.Generic.List Orders { get; } } }
IMPACT: Each domain model class would have to implement his related interface. i.e.,
public class Customer : SimpleOrder.Domain.Interfaces.ICustomer { public Customer() { _orders = new List(); } public int CustomerId { get; set; } public string Name { get; set; } private List _orders; public virtual List Orders { get { return _orders; } } }
PRO: Fixes Option 1's problem.
CON: This explodes the number of files (and the perceived complexity) in the project because each domain class now has an associated interface.
Option 3: Define the repository intefaces in the SimpleOrder.Domain
IMPACT: In order to inject the concrete repository classes into the application services layer (SimpleOrder.ApplicationFacade project) from the SimpleOrder.ConsoleClient at runtime, SimpleOder.ConsoleClient will ALSO need a reference to SimpleOrder.Domain.
PRO: This ALSO solves Option 1
CON: I was trying to avoid referencing the domain layer from the presentation layer directly because now the presentation layer can know too much about the domain layer. When I replace the console application in the future with a WPF or ASP.NET MVC app in the future, I risk second and subsequent presentation layer implementations from attempting to call methods in the Model instead of the Application Services layer. (However I do consider this in Option 4.)
Option 4: Put the interfaces in SimpleOrder.Domain, then reference the SimpleOrder.Domain from the SimpleOrder.ConsoleClient.
PRO: Fixes all the problems above.
CON: This doesn't feel right because I would be providing access from the presentation layer directly to the lower-level methods in the Domain layer when I should only be providing access to the higher-level chunky methods in the SimpleOrder.ApplicationFacade.
QUESTION I've tried each of these, but have settled on Option 4, HOWEVER that leaves a bad taste in my mouth about it. Is there a better option? Am I on the right track here?