With the design of a few large-scale service oriented architectures (SOA) under my belt, I have learned a couple of important lessons. Since it makes more than a single entry, I'm serializing them. Today: Not all services are equal. Intuitively, we can see that not all services are equal: a zip code lookup service doesn't feel as important as a customer registration service. Gut feelings are a great start, but formal distinctions are key when describing architecture. It is important to come up with a taxonomy that allows us to formally state how services differ. Honestly, I haven't done enough of these taxonomies be able to state if there are common threads in service taxonomy from architecture to architecture. I strongly suspect there will be - including the ones I discuss below - but I equally strongly believe that each architecture will have a unique taxonomy. One quick bit of terminology: I refer to all the services with the same set of taxonomy criteria values as service sets. This term has special significance in the ESB (enterprise service bus) world, as I'll discuss below. An obvious criterion in the taxonomy is the business function the service supports. I mean this in the broad business function sense: customer support, billing, fulfillment, etc. There will probably be multiple services supporting each of these business functions. Managing these as separate service sets make sense not just because of their business affinity but also because of the realities of support personnel, release schedules, legacy system alignment and other factors. Within business function alignment there is still room for further refinement. For example, you may need to distinguish between synchronous and asynchronous services. Asynchronous services are useful in business processes that have natural temporal boundaries (such as billing cycles) or are tightly aligned to legacy batch jobs. Allowing asynchronous services in other domains is interesting for supporting non-functional requirements such as high availability, as we will see below. One of the most subtle, but important, distinctions (again within business functions) is between read, write and calculate services. This criterion is particularly interesting because it aligns with disaster avoidance (DA) and high availability (HA). Distinguishing services between read, write and calculate (in conjunction with data replication and failover technologies) goes a long way toward DA/HA. When services are considered this way, it becomes immediately apparent which require data replication (read services) and which require failover (read and calculate). This may allow you to optimize the technical architecture; the hard problem to solve is around the availability of the write services. The read services may be made continuously available via data replication and failure; the calculate services through failover alone. Write services are different. In fact, I generally maintain that making continuously available write services is simply not worth it - a far better approach is to make write services explicitly asynchronous to allow for the non-availability of the write resource. This distinction is predicated on an assumption that you maintain a single master writeable database in a highly available cluster across geographic boundaries. In other words, one data center will remain the read/write master database, and the databases in other data centers will effectively be read-only replicants. This allows for unidirectional data propagation, which is still the least costly and most tested solution. With this constraint in place, you would funnel all writes to the master data center and allow the data propagation infrastructure to handle the synchronization; allowing for asynchronous write services allows that master data center to be offline for maintenance, batch jobs, or in response to a site-wide availability event (aka disaster). Of course you have to apply some common sense to this one. Calculate services may require access to some reference data - but reference data is by definition immutable at runtime and can be cheaply propagated. With these two criteria (business functional alignment and data access capabilities) we can begin to discuss the role of service sets vis-à-vis the enterprise service bus. Doing so will lead us to a definition of service granularity. The concept of "coarse-grained" and "fine-grained" services makes intuitive sense, but there isn't a good measurement for defining what services are coarse-grained and which are fine-grained. I'm going to defer the definition for a second, until we can discuss ESB implications, but I will return to it. The best function of the ESB is to arbitrate communication between service sets. Even within a business function, it does not make sense for services to call services in other service sets directly. Why? Because they have different services might have different service level agreements, deployment descriptors, and the like. For example, it would seem that a calculate service calling a read service might be harmless. But if you dig into it, the calculate service is purely stateless and can be run on a machine even if the database for that machine has been brought offline for maintenance. Clearly the calculate service can't access the database in this case; nor can it make the assumption that the read service it's going to invoke is on the same machine. In this situation, it is the role of the ESB to route the request to another machine, one that does have an active database connection. If you don't make this distinction, you tie the availability of the calculate service to the availability of the database, which weakens the overall availability of your service architecture. Is this level of restriction complicated? Absolutely. Is it overkill? Perhaps, depending upon your situation. Not all SOAs need this level of control over the communication between services. However, some do, and not having the concept of taxonomy severely limits the ability to formally describe which services form natural alliances. An architect designing a SOA that needs to address the issues of DA/HA needs to at least consider this level of control. Now, remember the fine- and coarse-grained distinction? This speaks to the communication of services within service sets. Within a service set, it does not make sense to utilize the ESB for service-to-service communication. Services are likely expressed in a technology that has native communication mechanisms that are highly performant; these technologies are also likely to be foreign to (or provide parallel functionality to) the ESB. The overall system performance can be improved (or, in legacy migration scenarios, maintained) to a large extent by utilizing these native technologies for service-to-service communication rather than the ESB. However, we have to know when this an appropriate shortcut to take. So, given the idea of taxonomy, fine-grained services are those services that are exposed only to other services within a service set. These fine-grained services may be invoked only via native technologies. Coarse-grained services are exposed to other service sets via the ESB as well. This does not mean that coarse-grained services cannot be called directly via native technologies in a service set; this may be appropriate. (Other architectural constraints, such as transaction management and initiation, may preclude this). I've tried in this entry to introduce the concept of service taxonomy and service sets. It is a very complex topic; I certainly can't do a complete job of addressing it in this entry. Applying taxonomy to services provides a formal mechanism for dividing a collection of enterprise services into service sets and defines the allowed interactions between those service sets. Very large SOA implementations should carefully define a set of criterion for distinguishing services at a high level and use these criteria to formally partition their services into manageable units.