Most of the technologies used for service-oriented architectures are fairly easy to implement. Web services, for example, uses XML and HTTP, both of which are fairly easy to understand and use. The problems start when we begin to design the interfaces for the services we want to create. Meeting the needs of all of the varied and numerous clients that use our services now and in the future is difficult.
One of the benefits of service-oriented architecture is service assembly. Developers assemble the services we create into working applications. Unfortunately, we don't always know how our services will be used in these applications. It is especially difficult for us to predict how our services will be used in future applications. This is one of the greatest challenges for us as service designers. We usually make our best guess as to how the services will be used when we are determining the way to structure their interfaces. Because services are executed across a network, it is especially important that we get the interfaces right. If we get them wrong, our clients will either receive more data than they need, or they will have to make multiple trips to the service to get all the data they need.
There are two ways to apply the concept of granularity to services. The service itself can be coarse grained or fine grained. This refers to how much functionality the service covers. Let's assume that we need to create an application for manipulating a bank account. Suppose the application needs to manipulate both a checking account and a savings account. We have two choices when we create a service to support this function. We can create a coarse-grained service called BankAccountService that manipulates both checking and savings accounts. Or, we could create two fine-grained services, a SavingsAccountService and a CheckingAccountService. Because BankAccountService supports the functionality of both checking accounts and savings accounts, it is a coarse-grained service.
Granularity also applies to the way that service methods are implemented. Suppose in our BankAccountService, we create a method called GetAccountHolder. A coarse-grained implementation of this function would return both the account holder's name and address. A fine-grained version of this function would return just the account holder's name. A separate method called GetAccountHoldersAddress would return the address. A service method that returns more data is a coarse-grained method. A service method that returns less, more specific, data is a fine-grained method.
Because services will be used in ways that we can't fully anticipate when we design them, the decision about granularity does not have to be black and white. Services do not have to be coarse-grained or fine-grained; they can be coarse-grained and fine-grained, or Multi-Grained. In other words, the BankAccountService, the SavingsAccountService, and the CheckingAccountService can all exist together. If a client only needs to access a customer's savings account, the client should use the SavingsAccountService. There is no need for the client to know anything about checking accounts. If, on the other hand, a client needs to know about both checking accounts and savings accounts, it should use the BankAccountService.
Why do we need to create the composite BankAccountService if we already have a SavingsAccountService and CheckingAccountService service? We should build services that are as easy as possible to use and meet the expectations of the clients that use them. It seems logical that a client would more often than not want access to both checking and savings accounts. By implementing both interfaces, we get the best of both worlds.
Initially creating fine-grained services and then wrapping them in coarse-grained facades accomplishes the creation of multi-grained services. For example, consider Diagram 1.
It is also possible to create fine-grained facades that access coarse-grained services. However, it is better to create finer-grained base services for reasons such as service deployment and management. Smaller services will provide more options for their physical deployment.
If we incorrectly predict the granularity of the service, clients will have access to more functionality than they absolutely need. This can be a problem if we have security at the service level. It might not be possible to restrict a client from some methods and not others, only to the entire service. If this is the case, we might have to open up the entire service to the client. This problem is avoided if we designed the service at the appropriate level of granularity.
The service interfaces constitue an established contract between the services and the clients. One of the tradeoffs when creating multiple interfaces is that each interface is essentially a published contract. Additional interfaces make managing these contracts between clients and services more difficult.