Where to put the interfaces in a component based architecture?
In a component based architecture where a large number of decoupled components communicate through a set of standardized interfaces - are there any guidelines for where-to-store / how-to-group the interfaces?
Extreme solutions would be:
- All in the same assembly (and off you go)
- One assembly for each interface
Both of these option seems wrong to me - the first being not flexible enough (for example if you want to change only one interface) the second being the other extreme, which could escalate to maintenance nightmare very quickly.
In particular, I am looking fo开发者_开发知识库r KILLER arguments not to adopt the two extremes above and obviously alternative approchaes.
Any opinions appreciated.
In a nutshell If the interfaces are shared then they have to be grouped in a common assembly, otherwise they have to be in the component interfaces assembly.
In a bit more detail If one of the standardized (i.e. shared) interface changes no matter where you put it you will have to change all the components which are implementing it, whether that interface is in a common assembly or in a component one. So there's no drawback specific to option 1, even if, as you say, you might have to change only one interface. On the other hand you would have a drawback by replicating common interfaces in every component, see standard redundancy issues.
This is not a special suggestion but a natural choice from the moment you chosen (wisely) to have standardized interfaces. You made the effort to identify them, you found they were standard, and now you group them.
If the components that implement these common interfaces have in addition some other ad hoc interfaces those will have to be in the component assembly as they shouldn't be exposed to the other components who have access to the common assembly.
IMO The interface(s) for the component should reside with the component - possibly in a component specific interfaces assembly.
Any "common" datatypes should live separately from the components (possibly in a "common" or "shared" component).
You would typically create some form of "common" library which all components in the architecture must reference. This is where all of the shared interfaces, enums etc. are defined and grouped.
So the first step of creating a library that extends or fits into the framework is to reference the Common.DLL. You then implement whichever set of interfaces you need in that particular module.
The extreme solutions that you describe are very extreme indeed. The first would be very inflexible and basically hobble the ability to extend your framework. The second would be very flexible but drown your project in a an annoying soup of single-interface DLLs.
All very good responses. And I would like to promote the general conscensus of "in moderation".
A quick anecdote however,
I have personally seen whole solutions explode with a proliferation of function-specific assemblies. I have also seen monolithic approaches. Reiterating: you want something in between.
In my personal projects, I use a lot of Dependency Injection [DI] and Inversion of Control [IoC], and leverage Castle Windsor Container to do a lot the heavy lifting. I also determine early on which components require a "broad" scope, and which ones do not require exposure. For instance, a service [say the container itself, or an event broker] would be considered "broad" as there are likely to be many many consumers of this service across the entire application. A component that is isolated [say a business-specific date formatter] would not be broad, as no one is interested in consuming it directly except the business it is specific to.
Broad interfaces, I would place in a separate SomeProductName.Interfaces
assembly.
Business-specific interfaces may be placed in their own function-oriented assembly SomeProductName.SomeStuffForAlice
and SomeProductName.SomeStuffForBob
, typically the same library as its implementation.
Assemblies are just a physical representation of source organization - they don't actually mean anything in and of themselves [ie a monolithic mash, though distgusting, is functionally equivalent to a well organized solution and the disturbing project per interface nightmare].
An organizational convention is only useful if it serves its consumer [you! the developer!]
Can't you group the interfaces into functional/domain areas? This way you would get a solution somewhere in the middle. If not, I would go with putting all common interfaces into just one assembly.
I use as few assemblies as possible, aiming for a single assembly while isolating volatile areas of the domain. When multiple assemblies are clearly appropriate or required, I do my best to group interfaces that will change at the same time into the same assemblies.
There's been some good discussion recently about the cost of maintaining multiple assemblies. This article is particularly good at describing the drawbacks of multiple assemblies, observing how they add costs at development time, compile time, deployment time, and runtime.
It depends on the purpose of each interface:
If the purpose of the interface is to define a standard protocol between a set of alternative suppliers and a single consumer, the interface is owned by the consumer.
If the purpose of the interface is to define a standard protocol between a single supplier and a set of alternative consumers, the interface is owned by the supplier.
If the purpose of the interface is to define a standard protocol between a set of alternative suppliers and a set of alternative consumers, the interface stands on it's own.
Finally, if interfaces are being used as a general approach to reduce complexity, they are typically owned by the consumers and should be defined as narrowly as possible such that each interface supports the consumer's needs in specific requirements context.
精彩评论