Jishnu Gee asked:
SA — Thank you for detailed explanation and I accept your solution. However, I want you to throw some light on isolating hardware driver and WCF program.
Well, those two things should be isolated as well, but this is simpler. So far, we mostly discussed architecture in the aspect of module and deployment isolation (tiers, actually). What you are asking now is a very different and, in my understandings, simpler aspect: layers architecture.
Basically, all units you create (assemblies, in this case), should be put in a stratified structure represented by some artifacts. In this case, projects and, say, directory structure where you put your project. Say, when you create a module which uses WCF to connect hardware units of certain type, you create some particular solution on some semantic layer. Why, after all, it is different from just the WCF? Because you bind semantic features of your hardware interface with WCF by creating some artifact, such as
service contract. This service contract is the semantic artifact which carry knowledge of how exactly, say, the instructions directed to the hardware are expressed in the form of data/service contract, how it is structured, and how the hardware response is structured. Roughly speaking, you will have WCF types for control and acquisition.
For general approach and the motivation of appropriate architectural solutions, please see my past answer:
How Do I Divide My Code Appropriately?[
^].
Please locate my considerations of vertical and horizontal arrangement of units. I probably did not mention one aspect: the build. If you simply put all your units in one solution, your structure is always built by dependencies, and more universal layers are built first, then less universal and more semantic. The dependency of units in the same layer should be undefined (otherwise they should be split into different layer).
Let's back to the place of your hardware and WFC. In the semantic layer (or one of those), you should define something which is specific to the hardware. What? 1) interfaces for one or another type of hardware, 2) semantic WCF types describing acquisition/control for this type of hardware. These two kinds of units should be on the closed semantic layers, but WCF types are a bit upper: WCF types can depend on the interfaces, but the hardware interfaces cannot depend on WCF types. (It gives you plenty of benefits. Don't couple to WCF too much. What if you still need hardware which is never connected to WCF? What if you later migrate from WCF to some newer technology of future? It's more likely that your hardware interfaces would be the same or change less.)
Now, horizontally, you have different types of hardware and different types of WCF. There horizontal units does not have to be even different assemblies. It just depends on the complexity of your interfaces. Let's see it on a simple example. Say, you have 1) motion system, 2) cameras and 3) digital I/O for control and acquisition of simple sensors. Minimally, you can have two projects and two library assemblies covering these topics: 1) set of hardware interfaces for motion systems, cameras and digital I/O, 2) set of WCF types (contracts, etc) covering control and acquisition for these types of hardware. So, each of these 3 types should be represented by two projects and two assemblies, but hardware of different types can be united with different hardware types in one unit.
No way you should put any implementations of hardware control in these layers! Instead, you should create sets of interfaces each covering
wide class of motion, visual and I/O hardware from different manufacturers. This is the most important idea here.
Now, where should you put implementations?
On the very top, in plug-ins layer! You can have a separate plug-in on each type of hardware of each manufacturer or, in some cases, separate for different product like of different manufacturer.
It's important to avoid one over-simplification seduction here. One may decide: "Oh, we are using only one I/O product of only one manufacturer. This product is very good, so I decided to use only this one, so please don't waste time, put it in your software directly, assuming there will be only one". Fight such arguments as strongly as you can. If it tends to happen, your role should be to save your team from
vendor lock-in, and not only that. Assuming that the hardware should always be the same is one of the worst typical mistakes.
All hardware units should be represented as plug-ins. But now, a plug-in does not mean a separate project and separate plug-in assembly. Usually plug-in technologies allow putting more than one plug-in (usually for the same set of implemented interfaces), so you can put them together, too. It's enough to have code for different units in different, say, source file directories.
See also my past answer related to plug-ins and other related answers on plug-in architectures:
Projects and DLL's: How to keep them managable?[
^].
See also at this specific open-source plug-in technology project:
http://en.wikipedia.org/wiki/Managed_Extensibility_Framework[
^],
http://mef.codeplex.com[
^].
—SA