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?