English 中文(简体)
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 for 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.





相关问题
Manually implementing high performance algorithms in .NET

As a learning experience I recently tried implementing Quicksort with 3 way partitioning in C#. Apart from needing to add an extra range check on the left/right variables before the recursive call, ...

Anyone feel like passing it forward?

I m the only developer in my company, and am getting along well as an autodidact, but I know I m missing out on the education one gets from working with and having code reviewed by more senior devs. ...

How do I compare two decimals to 10 decimal places?

I m using decimal type (.net), and I want to see if two numbers are equal. But I only want to be accurate to 10 decimal places. For example take these three numbers. I want them all to be equal. 0....

Exception practices when creating a SynchronizationContext?

I m creating an STA version of the SynchronizationContext for use in Windows Workflow 4.0. I m wondering what to do about exceptions when Post-ing callbacks. The SynchronizationContext can be used ...

Show running instance in single instance application

I am building an application with C#. I managed to turn this into a single instance application by checking if the same process is already running. Process[] pname = Process.GetProcessesByName("...

How to combine DataTrigger and EventTrigger?

NOTE I have asked the related question (with an accepted answer): How to combine DataTrigger and Trigger? I think I need to combine an EventTrigger and a DataTrigger to achieve what I m after: when ...

热门标签