jfaiga (6) [Avatar] Offline
#1
I liked the idea of enforcing loosing coupling as described in section 6.5.

What do you think of the following pattern:

Each C# Class Library is categorized into a category, eg:
* Definition
* Implementation
* Tests

Each Class Library must conform to a naming convention that allows determining the category from its name.

"Definition" class libraries typically include interfaces, abstract base classes, enums, exceptions, etc
"Implementation" class libraries include concrete classes.

Then enforce the following:
1. An "Implementation" class library cannot reference another "Implementation" class library. (It can however reference other stable dependancy class libraries).
2. Similarly, a "Definition" class library cannot reference an "Implementation" class library.

This way we enforce that "Implementation" class libraries can only referenced by composition roots.

If there is a specific scenario that we find we need an exception to rule #1 (perhaps adapter pattern), then we add it as an explicit exception to the rule.
mark.seemann (383) [Avatar] Offline
#2
Re: Monitoring coupling
What do I think about it? Well, basically, it it works for you, then by all means do it.

While I think that perhaps the rules you outline are a bit too restrictive for my taste, I don't think they are particularly malign. What I mean is that if you start following these rules, and later find out that you want to relax them a bit, you haven't painted yourself into a corner.

Don't get me wrong when I say that I find those rules a bit restrictive - I don't know your context, but I can definitely imagine situations (e.g. lots of junior developers on the team) where rigid rules might help maintain a certain degree of order.

When it comes to the separation of libraries, the most important separation is that between implementation and tests. These must (IMO) be defined in separate assemblies.

It's often also a good idea to separate interface definitions from implementations, but often a pure library for interfaces is overkill. Putting the interface definition in the library that consumes the interface is often good enough. It's only if you have a lot of different libraries that all consume the same interface that it makes sense to create a pure 'interface library'.