views:

1690

answers:

3

Just wanted to know how others have layered their architecture. Say i have my layers as follows:

Domain Layer
--Product
--ProductService (Should the imp go into this layer?)
--IProductService
--IProductRepository

Infrastructure Layer
--ProductRepository (Imp of IProductRepository in my domain)

Now when a new product is created i have a requirement to assign a product id by calling into the ProductService.GetNextProductId() method.

Because the service has a dependency on the repository i set up the ProductService ctor with an interface of IProductRepository which can be injected later. something like this:

    public class ProductService : IProductService
    {
        private IProductRepository _repository;

        public ProductService(IProductRepository repository)
        {
            _repository = repository;
        }

        public long GetNextProductId()
        {
            return _repository.GetNextProductId();
        }
    }

My issue is that when i use the service in the Product Class i am making reference to the Repository in the ctor when instantiating a new ProductService class. In DDD its a big no no to have such a reference. I' am not even sure if my product domain class is being set up correctly to call the service, can someone pls advise:

public class Product : Entity
    {
        private ProductService _svc;
        private IProductRepository _repository;

        public Product(string name, Address address) //It doesnt seem right to put parm for IProductRepository in the ctor?
            : base(_svc.GetNextProductId) // This is where i pass the id
        {
            // where to create an instance of IProductRepository?
        }
    }

How can i elegantly solve this design issue? I am open to suggestions from experienced DDD'ers

EDIT:

Thanks for you comments. I also doubted if the service should be called from the Product Class. I have not used a factory pattern (yet) as the construction of the object is still simple. I dont feel it warrants a factory method yet?

I' am confused...Putting the ProductId aside if my Product class needed some other data from a Service e.g GetSystemDateTime() (i know, bad example but trying to demonstrate a non db call) where would this service method be called?

Services in DDD are logic dumps where the logic is not natrual to the domain object, right? So How does it glue together?

+6  A: 

Your domain model shouldn't have a reference to ProductService nor to IProductRepository. If you create a new Product it has to be created through a factory - the Factory may use ProductService to get a product id.

In fact I'd wrap ProductService with an appropriate interface, such as IProductIdGeneratorService so that you can inject this into the factory using your IoC container.

__grover
THanks please see my comments above.
You're right about your addition of services as logic dumps. These services can then be used by the application running on top of the domain model or the infrastructure running below it. In your case I think either the app, teh factory or the repository can be made responsible for determining the product id. I'm more inclined to put it into the repository. If you store an entity in the db for the first time its the repos responsibility to assign it an id, this seems to be almost the same?
__grover
Ok so you are saying that i should generate the id outside of the domain class and pass it to the constructor as part of the creation. Whereas in my example i was trying to create the id as part of the entity which really doesn't fit?
Also want to add that in my example iam not using a Factory to create my product since it fairly simple. Should i opt for a factory even for simple sceanrios?
1. Yes.2. I personally do, but this is really personal preference. I'm trying to be a DDD purist there, which some consider bad.
__grover
Yes you should really not have references to services in your entities, these services are not part of the entity state.The factory solve the problem nicely.You can read this post about service injection in entities :http://thinkbeforecoding.com/post/2009/03/04/How-not-to-inject-services-in-entities
Think Before Coding
+1  A: 

If I understand your question correctly, you state that your Product class is calling the ProductService class. It shouldn't. You should do this in a factory class that is responsible for creating and configuring a Product. Where you call this method may also depend on when you want to issue the ProductId: We have what may be a similar case in that we need to get a number from our legacy accounting system for a project. I defer getting the number until the project is persisted so that we don't waste any numbers or have gaps. If you're in a similar situation, you may want to issue the ProductId in a repository save method instead of when the object is created.

As an aside, do you really think you'll ever have more than one ProductService or ProductRepository? If not then I wouldn't bother with the interfaces.

Edited to add:

I recommend starting small and keeping it simple by starting with two just classes, Product and ProductServices. ProductServices would perform all services, including factory and repository, since you can think of those as specialized services.

Jamie Ide
THanks please see my comments above.
+1  A: 

To your last point, services in DDD are a place to put what I describe as "awkward" logic. If you have some type of logic or work flow that has dependencies on other entities this is the type of logic that usually doesn't "fit" inside a domain object itself. Example: If I have a method on my business object to perform some type of validation, the service class might execute this method (still keeping the actual validation logic related to the entity inside its class)

Another really good example I always mention is the funds transfer method. You wouldn't have an account object transfer from one object to another, but instead you would have a service that takes the "to" account and the "from" account. Then inside the service you would invoke the withdrawal method on your "from" account and the deposit method on your "to" account. If you tried to put this inside the account entity itself it would feel awkward.

A great podcast that talks in depth about this very topic can be found here. David Laribee does a really good job explaining now only the "how" but the "why" of DDD.

Toran Billups
Thanks for the link. Will listen on my way to work on monday :p So the general consensus is that Domain Classes do not call into services, period.(?) You provided a good example of the Fund Transfer method, can u provide more details where exactly is the Transer(Account fromAccount, Account toAccount, decimal amount) method is being called? Within the domain, app, or infrastructure?
It will be called within the App in response to the request to transfer the funds.
__grover
Agreed, if you are using some presentation pattern like MVC or MVP it might be invoked inside the Presenter/Controller
Toran Billups