April 20, 2007
@ 11:15 PM
I have seen the following question on one of the forums I follow
"I have studied up on the SOA approach and it all sounds good.  But most articles stop at the theory.

Lets say I sell things.   I have a CustomerProfileService.   The application does CRUD through this service to a back end database.  Its autonomous and isolated.
I have anther service, InventoryItemProfileService.  Again, the application does CRUD through this service to a back end database. It is autonomous from the CustomerProfileService.  Not only may it live on a different DB from the CustomerProfileService, it might exist on a different platform.
Now lets get to the InvoiceService.  Lets say from the client side, I would guess that i would have a CreateInvoice(custID,itemID[] ) method.  The InvoiceService would then call out to the CustomerProfileService for profile that meets the needs of the invoice, then another call out to the InventoryItemProfileService for the item descriptions and such.

Here is the question.  It would seem like in the back end (the db) of the InvoiceService there would be tables to support the customer info and the item info from the invoice.  Where prior to SOA, when everything was in the same db, these requirements would be largely satisfied by joins.  Now a logical join across services just seems radically expensive (everytime you touch the invoice).  hence the need for the customer and item tables local to the invoice service.

Does this sound right?  Just how often does the InvoiceService have to go back to these other supporting services?"
I also got a comment with a similar theme on my Cross Service Transactions post.

I see a few problems with the way the services in the question are modeled (like CRUDy interface) but in the end it all boils down to the root cause -and the real problem: granularity of the services.

Sure when "a service" is too small it doesn't make sense to separate its tables from those of other services. it doesn't make sense to have transactions that span only what's internal to the service. It doesn't make sense to pay the price to make a service autonomous (like caching reference data from other services). When the granularity is too small you will often find that you need to make a loot of interactions with other so called services. you are more likely to have CRUDy interfaces.
You are also more likely to have slow performing solution and suffer from  low-availability.
Using services in a granularity mentioned above is, in my opinion, a nightmare that would probably make you work very hard to maintain  the SOA principles in place  - or the more likely option, that you would circumvent the principles so that you can get something maintainable, usable and performing (and flip the bozo bit on this all SOA thing)

So what is the right granularity. Well, it is not a one-size-fits-all kind of thing, but as a rule of thumb I would say anything just shy of a sub-system and up. A service has to have enough meat so that it would make sense having it autonomous; that the transactions would fit nicely inside its boundaries; that it would be worthwile making it highly-available; that you can pass a complete task/document to it and it won't have to talk to a gazillion other services to complete processing it; etc.

If your application's idea of invoices is a 2 tables one with a header and one with invoice details - then don't make that a service. if invoicing is a sub-system with complex business rules a lot of options and what-not - then it can be a good candidate

Think about it next time you design a service :)



 


 
Sunday, April 22, 2007 10:48:06 PM (GMT Standard Time, UTC+00:00)
Hi Arnon,

I've just read your blog n' msdn forum replies and wanted to get your opinion on the following within the context of what is being discussed in the forum:

1. I've been trying to investigate real-world services, and had looked at two prominent services implementation of MS CRM 3.0 and SalesForce AppExchange - they are both very CRUDy and (how one of anti-pattern mentions it as) "Loosey Goosey". First is the list of operations in the SalesForce API (from their documentation)

The following table lists supported calls in the API in alphabetical order, and provides a brief description for each. Click a call name to see syntax, usage, and more information for that call.

Note: For a list of API utility calls, see API Utility Calls.

Call Description
convertLead

Converts a Lead into an Account, Contact, or (optionally) an Opportunity.
create

Adds one or more new individual objects to your organization’s data.
delete

Deletes one or more individual objects from your organization’s data.
describeGlobal

Retrieves a list of available objects for your organization’s data.
describeLayout

Retrieves metadata about page layouts for the specified object type.
describeSObject

Retrieves metadata (field list and object properties) for the specified object type. Superseded by describeSObjects.
describeSObjects

An array-based version of describeSObject.
describeTabs

Describes the “apps” and tabs that have been configured for the user.
getDeleted

Retrieves the IDs of individual objects of the specified object that have been deleted since the specified time. For information on IDs, see ID Fields.
getUpdated

Retrieves the IDs of individual objects of the specified object that have been updated since the specified time. For information on IDs, see ID Fields.
login

Logs in to the login server and starts a client session.
query

Executes a query against the specified object and returns data that matches the specified criteria.
queryMore

Retrieves the next batch of objects from a query.
retrieve

Retrieves one or more objects based on the specified object IDs.
search

Executes a text search in your organization’s data.
update

Updates one or more existing objects in your organization’s data.
upsert

Creates new objects and updates existing objects; matches on a custom field to determine the presence of existing objects.

and here are list of operations supported by MS CRM 3.0

The following operations are supported. For a formal definition, please review the Service Description.

Execute
Executes business logic and special operations using a message-based approach. The Execute method takes a message request class as a parameter and returns a message response class.

Retrieve
Retrieves an instance of the specified entity.

RetrieveMultiple
Retrieves a collection of entity instances of the specified type, which meet the specified conditions.

Delete
Deletes the instance of the specified entity.

Create
Creates an instance of an entity.

Update
Updates the instance of the specified entity.

Fetch
Executes a query specified in the FetchXML language. The results are returned as an XML string.

As you can see they are neither proccess or task oriented, also noticable is that they aren't tied to any particular entity. What do you have to say about this, as a real-world example?

2. One word you mentioned was "meaty" - lately i've been doing some research on ESB, and looking at the literature on the web, it seems one should expose rather very specific task-oriented services. As an example again, consider the following operations for a Hotel Booking Service:

GetAvaliableHotels

GetHotelDescription

GetHotelRate

GetHotelReservationInfo

MakeHotelReservation

CancelHotelReservation

This seems to be quite specific, but as was the example orginally posted this will put you into the same trouble with having costly cross-service calls (say with other related services such as customer info, air booking, vehicel hiring etc). So the question is what is "meaty", is the specificity or the completeness/generality (such as the CRM examples above) of a service?

Now, what I think is that perhaps we should expose a bunch of Logically-Related-Services (LRS) atop a core business system - which would mean that each of the individual service is not autonomous, per se, but rather the lot as a whole is autonomous. And within/amoungst these LRS we can share (both internally and externally) schema (for say a customer entity, an order entity, an invoice entity etc.) to have much better performance, specificity, and business-model correctness? What do you think, is even technically correct to do so?

Rishi
Rishi
Comments are closed.