Tuesday, December 1, 2009

Some thoughts on service naming / service capability naming conventions (1/2)

A topic which has had a lot of discussions in the past and will still have a lot of discussions and disagreements for a long time to come, is service naming / service capability naming.

Recently I got another trigger on this topic: imho service naming which does not reflect the purpose of a service properly. A lot can be said about service naming and there are almost as many opinions to the subject as there are people interested in the subject.

This post tries to describe my personal humble opinion on service naming. You can agree or disagree and I'm willing to hear your comments, just leave me a comment and I'll be glad to take your input into this article.

Service naming is a very important subject for any SOA. Any self-respecting SOA architect has/uses a SOA reference architecture with service naming guidelines in it as it directly contributes to one of the most misunderstood but very important SOA design concepts: service (capability) discoverability. In the past, discoverability had lost a lot of its charms for architects and designers as the intended purpose (runtime) discoverability as a goal was never really reached in the way it was intended when initially conceived. Instead, nowadays, design time discoverability is becoming more and more important and service naming is one of the key concepts for defining discoverable services. If the service name does not properly match the scope and purpose (the core logic implemented by the service), discoverability becomes inherently more complex. If your service name is chosen wisely, the service sells itself better (real life example: if a hotel is not properly/oddly/ambiguously named, you will probably skip it when you are browsing the hotel directory for a place to sleep, especially if the hotel is called "amour toujours").

In this post we will use the following structure and definitions when referring to services:

service::capability where:
service - represents the unit of service logic to which the SOA concepts 'have been applied to a meaningful extent' as per Erl's definition :).
capability - represents the operation(s) which can be performed by the service.

Some examples of bad service names are service names which are
- scope and context issue: Inventory (what is the scope of "Inventory"? Just managing inventory levels? Or inventory locations, both, something else?)

- core logic: ::update (what does it update? even if we know the definition of the service itself, what is the service context in which updates happen here?)

- ambiguous naming: OrderManagement::execute (what is it that the order management service is actually executing? Ie. execute order fulfillment or ordering?)

How can we deal with this problem? How do we prevent these problems from being created in the first place?

One answer to this question (besides "governance"), is to define naming rules and conventions  (which must then be appropriately governed). Before starting  the actual discussion, we need to understand that different kinds of services exist and they are meant to perform different types of logic. I will use the "Erl" definition here which distinguishes between Entity Services, Task Services and Utility Services. More service models can be created but I have intentionally stuck tot he basics. Roughly, you can take these assumptions for this post:
- Entity service: performs their capabilities on business entities like Customer, Invoice, Order etcetera.
- Utility services are services for 'shared system logic' or cross-cutting technology services like logging, notification etc. They help the system to be operable while separating concerns like notification out of the other service types.
- Task services perform operations triggered by and executed in a certain (business) process - hence they contain business (process) logic.

Below you can find some suggestions to setup such a guide for designers to follow. I'm happy to receive any feedback on these.

As said, whether it be services, or service capabilities, apply naming standards. Don't do it for one and not for the other as it is useful for both.

Service Names should place the service capabilities in the appropriate context and define the service scope wisely. Knowing this is not a smart statement, I can say that this is up to you. Service names should be assigned differently, depending on service type (Erl definition of service types):
  • Entity services - use the [entity name] service naming like Order, Invoice etc.
  • Task services - use the [process name] service naming like OrderManagement, Collections Management, Credit Management etcetera. It's perfectly fine to sub-categorize if necessary, like in this example: OrderFulfillment instead of Order Management.
  • Utility services - use the [verb-or-noun] service naming like Notification, Logging etc.

Regarding service capability naming, apply the following pattern:
The verb is used to indicate what happens to the noun.
The noun is used to indicate, to what the verb is applied.
The (optional) subject allows for distinguishing between different logical subjects which may be meaningful to use for certain nouns).
Sometimes, this paradigm seems insufficient, ie. in case of notifications - see proposals below. Try to find a pattern which suits your needs.

Examples are:
- readOrder
- readOrderHeader
- readOrderLines
- updateOrderCustomer
- updateOrderPricing
- updateOrder
- notifyOrderUpdate or sendOrderUpdateNotification
- receiveOrderUpdateNotification

Note that when we expect readOrder to return an entire order structure, updateOrder expects to update an entire order datastructure. I would be concerned if these would be the only two operations I could perform on an order, referring to the service granularity concern: these would cause issues in that area: an updateOrder service would probably be much to big to be useful from a true SOA design principles point of view, but feel free to discover this yourself. Let me make the following statement: if you only need to update the shipping address on an order, and for you to do that, you had to read the entire order, change the applicable order parts and then save the entire order, you are most likely heading down the wrong path regarding service granularity. Continuous evaluating and re-evaluating the granularity of services and service capabilities is a constant factor anyway as the only constant factor we value is "change" ;)

Whether the service capability name may repeat (part of) the service name remains a debate on itself. An example of this is OrderManagement::updateOrderShippingAddress. Typically, the service name implies the context for the capability, making it useless to repeat the service name in the capability name. Applying this to the example would result in the OrderManagement::updateShippingAddress name.

For entity services, I can give one additional advice: try to use standardized (predictable) names, purposely chosen to make it easier for designers to define them for any other entity service. A suggestion for entity services would be: create, read, update, delete (aka. CRUD).
Following this kind of an approach reduces the number of discussions you will have on service naming. In fact, apply this predictable naming concept to all service types whenever possible, by establishing a standard vocabulary. Especially the verb naming requires some extra attention as there are many ways to explain similar behaviour using different verb names. If the intended behaviour is the same, then use the same name. Do not use aliases for the standard verb names unless it removes ambiguity if the standard verb name is used.

Examples of predictable verb names in a vocabulary are:
Get - retrieves data
Retrieve - same as get but discouraged: name too long which makes it hard to read service capability names.
Notify - creates a notification
Create - creates something (and in case of entity service, may store records in a database)
Update - updates something synchronously
Post - updates something a-synchronously as in fire-forget mode

A service capability name must describe what the core service logic does, not what the consumer does. Recently I have been involved in a discussion on service naming. Suppose we have a service exposing events about changes in a customer database object the Entity Service's service and capability names would be similar to CustomerService::postChangeNotification. This service name indicates that it is related to Customers; the service capability name indicates that it is sending notifications about changes on the service's underlying distinct functional scope: the customer objects. The replication service capability consuming these events would probably be named something like OfflineCustomerPortalCacheReplicationService::processCustomerChangeEvent. (Please don't flame me for insanely long names). The service name is referring to an underlying object "offline customer cache" and also the service is responsible for replication ( this would most likely be a utility service). The service capability name indicates that it processes the events fired by changes on the customer object (as generated by the CustomerService), in the context of the replication service for a certain offline customer cache for the portal (this example could be the implementation of a forward cache pattern).

Last advice: please remember not to try defining services and service names in splendid isolation! Get other people's opinions and make sure that you all (well, most of the lot anyway) agree to avoid different naming by different project members even if they are in the same team! This obviously also applies to other architecure and design activities you and your team members do.  Perhaps it's a good idea to setup the naming guidelines together. The discussion around service capability naming will probably never go away, but at least you will apply the same set of concepts and rules to service naming and service capability naming. In the end, life will be easier I hope.