Recently, I have been working on an SOA project using WCF. As development moved toward integration of multiple services I found the coupling of services to be a real pain point. Although services operated in a loosely coupled fashion, the actual implementation of the services was less ideal.
The system encompassed a set of services organised into Process and Entity layers. The design did not include utility services but utility logic was separated into a shared utility library. This was not intended to be enterprise-wide but represented the shared logic of this particular development effort. The library included common logic for hosting services, installation, supporting SOAP faults and supporting redundant deployment.
The initial design effort established the functional service boundaries and the compositions that would achieve the required functionality. An Inversion of Control container (Microsoft Unity) was used to provide dependency injection.
Individual services were modeled as three separate .NET assemblies. One for each of contract, service and client. The client was a small adaptation of the standard .NET generated code that enabled automatic retries in a redundant deployment. I decided sharing the contract assembly and avoiding the automatic generation of proxies would provide a more effective development experience, although the services could be accessed by the generated WSDL directly by other consumers.
The first problem encountered was that in order to build the project the corresponding contract and client assemblies were needed in the Visual Studio solution. Without a centralised repository, this introduced cross-solution build dependencies.
The second problem was that developer testing was far more complicated. Our developers were working in different geographies with different network connectivity. It was not desirable for all development to work directly on an integration platform, but this situation was not helpful either.
Thirdly, we had included support for distributed configuration but simplified use of WCF depending on configuration files was complicated because those configuration sections couldn’t be loaded dynamically from the remote configuration store. I know how to manually create service clients, but that wasn’t the point! I know other people have had problems with this too… There was a similar issue with Unity.
Fourthly, several services depended on several other services. Sometimes these were part of the execution of a single process. In other cases, messages were sent as notifications only. One example was that a caching system was notified of various changes. This caused a problem in that the service implementation needed to be aware about all these other systems.
The SOA approach applied produced a successful design, however some problems could have been avoided.
The “inversion of control” approach really did not help with decoupling the system. Instead, it just became another part of the system to configure. It was useful in order to bring certain configuration options out of the code, but it did not address service coupling (as opposed to component coupling).
A controlled service inventory and library, possibly including compiled clients and data objects, would reduce the dependencies between solutions.
The use of a central routing subsystem, whether an ESB or a separate service implementation, would have reduced the dependencies between services while enabling later adaptation of compositions and orchestrations. The use of queued messaging would have further helped in this, particularly in respect of fault tolerance (redundancy). Either orchestration or a publish-subscribe approach to notification would also have been beneficial.
In the absence of an EAI or ESB implementation, something may still need to be done to address WCF configuration. The upcoming Microsoft Dublin technology may address this pitfall separately.
I also think there is value in limiting what is made visible across service implementations. Governance processes to minimise this “white-box” approach would have given momentum to a solution to these problems.