Reputation: 181
My company has an application that allows users to perform a diagnostic medical test that measures circulating blood volume. This test involves using a gamma counter to measure/count the radiation in multiple blood samples. These samples are placed in a motorized carousel (i.e., sample changer) that moves the samples over the gamma counter to be counted.
Here’s what we believe our domain nouns are:
We believe our domain verbs are:
As we understand domain driven design, the business logic should go in the domain. Our business logic resides mainly with what we’re calling a test execution controller. This controller uses a test execution context to determine how to move the samples into position and to have the gamma counter measure them.
The specific technologies that are giving us some confusion are Prism and WCF.
(1) Prism relies on an event aggregator to pass non-CLR events around the system. The test execution controller uses this to let other parts of the system know what’s going on (e.g., Sample 2A is being counted, there are 34 minutes remaining for the current test). Technically, the event aggregator is a technology that’s part of Prism, and domain objects/services are not supposed to rely on technology.
Question: Is there a way to restructure things so that our domain service isn’t technology-dependent?
(2) We have two WCF services that allow us to communicate with the sample changer and gamma counter. Each service has a contract (i.e., an interface that’s decorated with WCF-specific attributes). At least with the contracts, we separate the concerns such that our main application depends on behavior, rather than a specific sample changer or gamma counter. However, WCF is a technology and the application code needs to know that this service we’re talking to is a WCF service (which is done by creating a proxy class). To satisfy DDD constraints, we end up having several similarly named classes/interfaces that seem redundant. Here’s an example
Question: We have interfaces in the domain and on the WCF side that basically have the same method names. Is there a better/cleaner way to do this?
Upvotes: 0
Views: 482
Reputation: 37719
An additional axis of structure to consider within a solution is the set of application layers. For example, it appears that in this case you have a presentation layer (implemented using Prism/WPF), a service layer (implemented by WCF) and a business/domain layer (implemented using DDD).
Is there a way to restructure things so that our domain service isn’t technology-dependent?
If the test execution controller is a controller in the MVC sense, then it should not contain business logic. Instead, its job is to coordinate interactions between the UI and the business layer. In this particular case, the controller should forward commands to the business layer through a WCF implemented service layer. However, the controller itself is part of the presentation layer and so the fact that it depends on a technology specific component such as the event aggregator isn't a problem since you've already chosen WCF/Prim as the technology for the presentation layer - there is no point to abstract it, especially prematurely.
We have interfaces in the domain and on the WCF side that basically have the same method names. Is there a better/cleaner way to do this?
Normally this type of dual-class hierarchy results when a DDD business layer is exposed as a service via WCF because you create DTOs (data contracts) which map to domain entities and values. The DTOs don't have behavior, their central role is to represent data coming in and out of a service. Many times a DTO will look very similar to the corresponding domain object and it is acceptable to have this duplication. If this is still a concern you can look into a mapping library such as AutoMapper.
As far as organizing the solutions you have a few options. One is to hide the domain layer completely from the presentation layer and only allow access to it through the service layer. So the presentation layer project (WPF/Prism) would reference a thin project which contains the service contract and the associated data contracts (DTOs). This can be a small project which defines the "schema" of your service layer. This project would also be referenced by the WCF project which implements the service contract. The benefit of this approach is that the domain is entirely encapsulated by the service layer. You can change the implementation of the service contract by re-deploying your service - no need to redeploy the presentation layer as well. The drawback is that it might be overkill or it might not be appropriate for the domain to be exposed as a service.
Also, I'm a little confused by your naming conventions and structure. For example, GammaCounterProxy isn't a proxy, the proxy is generated by WCF when you get a reference to the service contract IGammaCounterService. The service implementing class itself is just an implementation, not a proxy. Also, it seems wrong for GammaCounter to inherit from GammaCounterProxy. It would make more sense for GammaCounter to implement IGammaCounter directly, and have that object be used by GammaCounterProxy (renamed to something like GammaCounterImpl). The job of GammaCounterImpl is to process some command (represented by the DTO parameters). It would do that by loading all appropriate domain objects, such as GammaCounter, invoking methods on them, and then possibly returning a result (as a DTO) which would then be processed by the presentation layer.
Upvotes: 0
Reputation: 10984
WCF can allow you to separate your concerns quite nicely by exposing your services via endpoints. These endpoints can support:
For example, in my Magic8Ball WCF sample, I expose the Magic8Ball Service via several endpoints simultaneously: binary-XML/TCP for (very) fast access from WCF clients, XML/HTTP for non-WCF clients, JSON/HTTP for REST clients.
These endpoint configurations can be expressed entirely in your app.config should you wish so that you don't have to modify your source code & rebuild/redeploy your services should your environment needs change.
So, each of your "controllers" could be exposed as services and each of your nouns as serializable data entities. If you eliminate all but the most fundamental of your business logic from your nouns, then any calling application on any platform should be able to form a correctly formatted message containing data encoded in the correct format and deliver it via the supported transport to your service.
In this way, you can achieve a great deal of technology abstraction such that should you choose in the future to build some part of your system using a different technology/platform nothing in your environment should care much so long as the wire protocols are adhered to.
Upvotes: 2