views:

347

answers:

6

We work on a middle-size project (3 developers over more than 6 months) and need to make following decision: We'd like to have interfaces separated from concrete implementation. The first is to store the interface in a separate file.

We'd like to go further and separate the data even more: We'd like to have one project (CSPROJ) with interface in one .CS file plus another .CS file with help classes (like some public classes used within this interface, some enums etc.). Then, we'd like to have another project (CSPROJ) with a factory pattern, concrete interface implementation and other "worker" classes.

Any class which wants to create an object implementing this interface must include the first project which contains the interfaces and public classes, not the implementation itself.

This solution has one big disadvantage: it multiplies the number of assemblies by 2, because you would have for every "normal" project one project with interace and one with implementation.

What would you recommend? Do you think it's a good idea to place all interfaces in one separate project rather than one interface in its own project?

+5  A: 

Yes, I think this is a good idea. Actually, we do it here all the time, and we eventually have to do it because of a simple reason:

We use Remoting to access server functionality. So the Remote Objects on the server need to implement the interfaces and the client code has to have access to the interfaces to use the remote objects.

In general, I think you are more loosely coupled when you put the interfaces in a separate project, so just go along and do it. It isn't really a problem to have 2 assemblies, is it?

ADDITION:

Just crossed my mind: By putting the interfaces in a separate assembly, you additionally get the benefit of being able to reuse the interfaces if a few of them are general enough.

Maximilian Mayerl
+1 for mentioning Remoting. (Edited to fix typos)
TrueWill
+6  A: 

I wouldn't do it unless it offers a proven benefit for your application's architecture.

It's good to keep an eye on the number of assemblies you're creating. Even if an interface and its implementation are in the same assembly, you can still achieve the decoupling you rightly seek with a little discipline.

Jeff Sternal
I have to agree with you, Jeff. It turned out that a big number of assemblies does implicate a lot of problems.
Thomasek
+3  A: 

I think it you should consider first whether ALL interfaces belong to the 'public interface' of your project.

If they are to be shared by multiple projects, executables and/or services, i think it's fair to put them into a separate assembly.

However, if they are for internal use only and there for your convenience, you could choose to keep them in the same assembly as the implementation, thus keeping the overall amount of assemblies relatively low.

Rob van Groenewoud
Actually what I was talking about were public interfaces only. The private ones, if there are any, are contained in the project with the implementation itself.
Thomasek
Ah, I see. In that case, stick with the accepted answer :-)
Rob van Groenewoud
+1  A: 

There are pros and cons to the approach, and you will also need to temper the decision with how it best fits into your architectural approach.

On the "pro" side, you can achieve a level of separation to help enforce correct implementations of the interfaces. Consider that if you have junior- or mid-level developer working on implementations, the interfaces themselves can be defined in a project that they only have read access on. Perhaps a senior-level, team lead, or architect is responsible for the design and maintenance of the interfaces. If these interfaces are used on multiple projects, this can help mitigate the risk of unintentional breaking changes on other projects when only working in one. Also, if you work with third party vendors who you distribute an API to, packaging the interfaces is a very good thing to do.

Obviously, there are some down sides. The assembly does not contain executable code. In some shops that I have worked at, they have frowned upon not having functionality in an assembly, regardless of the reason. There definitely is additional overhead. Depending on how you set up your physical file and namespace structure, you might have multiple assemblies doing the same thing (although not required).

On a semi-random note, make sure to document your interfaces well. Documentation inheritance from interfaces using GhostDoc is a beautiful thing.

joseph.ferris
We don't have such strict rules like producing assemblies with productive code only. Our main purpose was to separate the assembly from its implementation. And yes, we try to document them well:)
Thomasek
I'm glad we don't have that rule where I work now, too. ;-)
joseph.ferris
+2  A: 

We used to have quite a number of separate assemblies in our shared code. Over time, we found that we almost invariably referenced these in groups. This made more work for the developers, and we had to hunt to find what assembly a class or interface was in. We ended up combining some of these assemblies based on usage patterns. Life got easier.

There are a lot of considerations here - are you writing a library for developers, are you deploying the DLLs to offsite customers, are you using remoting (thanks, Maximilian Mayerl) or writing WCF services, etc. There is no one right answer - it depends.

In general I agree with Jeff Sternal - don't break up the assemblies unless it offers a proven benefit.

TrueWill
+3  A: 

I would distinguish between interfaces like this:

  1. Standalone interfaces whose purpose you can describe without talking about the rest of your project. Put these in a single dedicated "interface assembly", which is probably referenced by all other assemblies in your project. Typical examples: ILogger, IFileSystem, IServiceLocator.

  2. Class coupled interfaces which really only make sense in the context of your project's classes. Put these in the same assembly as the classes they are coupled to.

    An example: suppose your domain model has a Banana class. If you retrieve bananas through a IBananaRepository interface, then that interface is tightly coupled to bananas. It is impossible to implement or use the interface without knowing something about bananas. Therefore it is only logical that the interface resides in the same assembly as Banana.

    The previous example has a technical coupling, but the coupling might just be a logical one. For example, a IFecesThrowingTarget interface may only make sense as a collaborator of the Monkey class even if the interface declaration has no technical link to Monkey.

My answer does depend on the notion that it's okay to have some coupling to classes. Hiding everything behind an interface would be a mistake. Sometimes it's okay to just "new up" a class, instead of injecting it or creating it via a factory.

Wim Coenen
+1 for throwing Feces at programming problems ;)
Nate Bross
Intereseting opinion! I would probably do it as you propose.
Thomasek
It's definitely a good idea to move infrastructure types (such as `ILogger`, `IFileSystem`, etc.) into different assemblies than domain-specific types, but you should still probably put `ILogger` in the same assembly as your concrete `Logger` implementations unless there is a specific reason not to (for example, because one of the concrete implementations will change a lot, in which case it might make sense to isolate that class in a separate assembly).
Jeff Sternal