When implementing services there are a number of practices I like to adopt. I have already discussed the use of interfaces to define the service contract. This post is to discuss the granularity of the contracts in a system.

In all but the most trivial of systems multiple service actions will be required. In providing these actions we can choose a position on a continuum. At one end we have a single contract that has all the actions as methods. At the other end we have a separate contract for each action. In between we have contracts that provide subsets of the actions. We must therefore make a decision as to where on this continuum we wish our system to be.

The single contract that provides all actions is unwieldy and results in code that is difficult to understand and modify. I’d love to claim that this is a deliberate exaggeration that no one would ever do in practice but 9000+ line counter-examples I’ve encountered would make that a lie. Nevertheless this end of the continuum involves a complete lack of separation of concerns and demonstrates terrible maintainability.

The question therefore is whether the other extreme is similarly bad and that an intermediate position with multiple contracts each containing multiple actions is the reasonable solution. I’ve certainly encountered the argument that having a single action per service interface will result in an unmanageable number of interfaces and classes. This argument holds that complexity of a large number of service interfaces is very high and hence we must consolidate them in order to make the complexity manageable.

This position reminds me of political compromise where there is often a view that the centerist position between two extremes is preferable. I wont comment on the relative merits of this view in politics but I will assert that I do not believe it to be applicable here.

I do not agree that many interfaces and classes is in this case more complex overall. Each class that implements a service interface will be less complex as it is now responsible only for a single action. Although there are more classes it is my contention that this implementation is overall simpler as all the elements of any service class are directly associated with the single action of the relevant contract. As the number of actions on the interface increase the number of concerns in the class not relevant to a selected action will also increase. This makes maintaining the service more difficult as the number of concerns increases the cognitive overhead of reasoning about the implementation.

I also do not agree that fewer service interfaces is inherently simpler. Fine grained service contracts that are properly named can increase readability through additional information carried in the name. A service that requires an IShoppingCartService may be doing anything to the shopping cart. A service that requires an IClearShoppingCartService has a clearly indicated requirement to be able to clear the shopping cart contents. An additional benefit is that it can be determined from the number of dependencies that a service is dependent on too many external actions and that refactoring may be applicable.

It may be suggested that dealing with a large number of services is difficult, error prone or inefficient. Again I do not agree. A decent Dependency Injection framework with automatic registration and wiring will handle the vast majority of the instantiation with some simple conventions (StructureMap, my current DI container of choice, has some very nice options for this). In general avoiding considerations such as circular dependencies can be managed by avoiding circular references between namespaces and between service types within namespaces.

Many service interfaces will mean many more service class instances to be instantiated. It is highly unlikely that this will be an efficiency issue. Stateless instances are cheap to instantiate and unlikely to be a significant resource problem in your application. It is much more likely that resource utilisation in the business logic will be orders of magnitude higher and a much greater concern in considering efficiency and performance.

I therefore find that in the general case it is preferable to have a single action per service interface as this is the least complex and most maintainable option. However there are notable exceptions. In particular this is not (at least currently) my preferred option when dealing with communications using WCF.

When defining a service contract in WCF there are a number of additional concerns that do not apply to general services, such as the configuration of endpoint addresses and communication channel properties, as well as the metadata to be defined on the service contract and implementation. This additional overhead means that there is additional complexity as the number of service contracts increases. As such a single action per contract is generally not the least complex option.

Even in this exception I would not start reducing the granularity of business logic. My WCF services are generally facades that invoke business services rather than contain business logic themselves, and these business services would continue to have a single action per service contract.

It should also be noted that having a single action on the service interface does not imply a single method on the implementing service class. The service class may have whatever methods make sense to effectively implement its function. Only one of these methods will be exposed (via the contract) to other types.

Rhys Campbell has recently discussed, both in response to my post on interfaces and on his own blog, explicitly implementing interfaces so that you will have compile time errors if a method is removed from an interface but is maintained on a class that implements the interface. At least for services I don’t favour this approach as for a service interface with a single method if that method is removed then the interface itself is unnecessary. Hence I don’t feel explicit implementation is actually beneficial here. I can see value for other classes of interface which have multiple methods, but I’m currently unconvinced that the additional complexity of working with explicitly implemented methods is justified by what I see as relatively small benefits (compiler detection of obsolete methods, not removal of code bloat). It will be interesting to see if Rhys has further thoughts on this topic.