views:

93

answers:

4

In my system I have two different projects, one defining its interfaces and another defining its domain objects. So far I managed to have the interface definitions independent of the domain objects but I am feeling now the need to include certain domain objects either as parameters of the methods defined in the interfaces or as return values of such.

Should I resist and try to keep interfaces independent of the domain objects or is this a unfounded concern?

EDIT - after posting the question I thought about defining an interface for each domain object, this way they can kept separate - don't know if it is overkill or if it is the price to pay so they remain independent.

EDIT # 2 - I was asked to give an example so I'll try to keep it simple. I have a process that handles image transformation and one of my domain objects is a class that holds information such as resolution, list of pages, hash, etc. Let it be called DocumentInfo. I have a class that uses DocumentInfo to perform actions such as GeneratePdfFromTiff; I had defined GeneratePdfFromTiff first as an interface method of IImageHandler, which is then implemented by ImageHandler.

The problem is - one of the parameters to GeneratePdfFromTiff is DocumentInfo. Here I have the method defined at the interface level having to be aware of DocumentInfo which was defined at the domain level. This is the kind of dependency I am concerned about.

+2  A: 

I would keep in mind the interests of the software engineers using the interface. Trying to decouple can make the code more abstract, and usually more difficult to consume. That means that more code will need to get written to "get stuff done", and that code will require more effort to write.

Pardoxally, due to the extra complexity, it will also get harder to change things, because more lines of code depend on your domain's visible interface. This is kind of the opposite of what you probably want to achieve, because the decoupling should help to make the system easier to understand and maintain (among other things).

But it really really depends a lot on what types you intend to expose, and to whom. Could you give some examples?

jdv
+3  A: 

This is a tough one, I'll give a try. +1 for the question.

Domain Models should know how to interact with each other's inner workings if they do it in the real world I think. That, of course, depends heavily on your exact domain model, because different models of the same thing would come up with very different representations.

The issue with the interfaces for each domain model class is that your domain model itself is already a specific view on reality, just like the interfaces. An interface is only valid within that specific domain. You can't use the same ICar for transportation planning, household-income calculators and car aerodynamics optimization.

Therefore, I doubt it is very useful to isolate their dependencies too far.

From what I know, interfaces are mostly (always?) public, which gives rise to access issues. The interface should not expose details about the implementation, but the domain model classes contain the actual implementation. Thus, instead of 'just accessing some value', you'd have to create another abstraction mechanism for each and every detail. You can't, for example, access any ID, User, etc. in the system. You'd need an abstract ID type, an ID Provider, etc. I believe this could be extremely cumbersome in a large real-world model.

Certain 'natural domain borders' should still be isolated, of course. If you build a social text editor, all domain classes that would also occur in a traditional text editor should be completely isolated from the social-network related items. Thus, the text-editor should only know an IUser. But I guess I'm not telling you anything new...

This is not too satisfying I'm afraid, but it seems it is essentially a thin line to walk.

mnemosyn
+1  A: 

You may actually need to. If your Domain Model references the interface library, you can't reference the Domain Model from the interface library, as that would create a circular reference.

Even if this isn't the case, referencing the Domain Model from the services creates a hard coupling between the interfaces and the Domain Model. This means that anyone implementing or referencing the interfaces also reference the Domain Model. You may not want that.

I would definetely recommend that you extract interfaces from those domain objects you would like to use together with your interfaces.

If you already have a class called Foo, then extract and interface IFoo from it, and use it in your other interfaces:

public interface IMyService
{
    public IBar DoStuff(IFoo foo);
}

Once you start using domain objects as interfaces, you will discover that there may be more places where you can replace the concrete class with the interface. Every time you do that, your code becomes more loosely coupled, and that's a good thing. It makes your code more maintainable, and more adaptable to change.

When you extract an interface, remember that you must perform a deep extraction.

If Foo looks like this

public class Foo
{
    public Baz Baz { get; }
}

the interface should look like this:

public interface IFoo
{
    IBaz Baz { get; }
}

public interface IBaz {}

(apologies for the C# code if you write in a different language...)

Mark Seemann
@Mark - thank you for your answer, it validates one of my options that would be to create an interface for each domain object *that can be used* by an interface. And BTW no apologies needed - I am working in C# :)
Otávio Décio
+1  A: 

I'd recommend defining interfaces for domain classes that have behavior, but not for simple container classes or value types.

If GeneratePdfFromTiff just treats DocumentInfo like a parameter object and the document information class doesn't have any logic, it should just be a publicly-accessible type.

If the document information class performs calculations or does anything else interesting, it's definitely worth extracting an interface. (For all the excellent reasons Mark mentions in his answer.)

Jeff Sternal
@Jeff - thank you. I understand the parameter object issue regarding DocumentInfo, but wouldn't it also be part of the Domain even though it may not have much of a behavior?
Otávio Décio
I agree that it should be part of the domain - I just don't think there's any value in decoupling it via an interface if there isn't behavior to encapsulate.
Jeff Sternal
@Jeff - but that's the conundrum - if it is defined at the Domain, it can't be referenced by the Interface because it would create a circular dependency, unless it has its interface extracted.
Otávio Décio
Oh, argh, I wasn't even paying attention was I? D: I suppose I'd think about combining them into the same assembly or extracting the DocumentInfo class into a separate assembly.
Jeff Sternal
@Otávio - on second thought, given what you've described, I suspect that `DocumentInfo` is part of a more general conceptual domain than the one expressed in your current domain assembly.
Jeff Sternal